Recker
Recker

Reputation: 1975

Templatized constructor unable to perform conversion

Here is a standalone use case of what I am trying to achieve

//Bar.hpp

#ifndef BAR_HPP
#define BAR_HPP

constexpr bool areNamesEqual(const char* name1,const char* name2)
{
    return ((*name1 == *name2) && (*name1 == '\0' ||  areNamesEqual(name1 + 1,name2 + 1)));
}
#endif

Then I have a class which uses this comparison utility as follows

// Foo.hpp

#ifndef FOO_HPP
#define FOO_HPP

#include "Bar.hpp"

class Foo 
{
    public:
    template<typename T_0>
    Foo(const T_0 & var_0)
    {   
        static_assert(areNamesEqual(T_0::formatter_name,"Hole"),"Incorrect hole type supplied!");
    }   
};

#endif 

Finally I have another class, which actually provides an argument for the comparison as follows

// Hole.hpp

#ifndef HOLE_HPP
#define HOLE_HPP

class Hole {
    public:

        Hole(double dx) : d(dx) {}

        static constexpr const char* formatter_name = "Hole";
    private:
        double d;
  };
#endif

In my main.cpp when I invoke this as below

//main.cpp
#include "Foo.hpp"
#include "Hole.hpp"

int main()
{
    Foo f(43);
    return 0;
}

g++(6.3) with --std=c++14 gives me following error

In file included from main.cpp:1:0:
Foo.hpp: In instantiation of ‘Foo::Foo(const T_0&) [with T_0 = int]’:
main.cpp:6:13:   required from here
Foo.hpp:12:36: error: ‘formatter_name’ is not a member of ‘int’
         static_assert(areNamesEqual(T_0::formatter_name,"Hole"),"Incorrect hole type supplied!");

Why cant the compiler convert double type to Hole class implicitly ? I am not sure if conversion operator of Hole class would help me out here.

:UPDATE: Updated the snippet to show the error for int literal.

Upvotes: 1

Views: 57

Answers (1)

Ad N
Ad N

Reputation: 8396

Let's analyse the compiler error:

Foo.hpp: In instantiation of ‘Foo::Foo(const T_0&) [with T_0 = int]’:

Means T_0 is deduced to type int (side note: are you sure you are not giving the error when you tried with 43 literal, instead of 43.0?)

So, the type of T_0 is fixed from here. Then:

Foo.hpp:12:36: error: ‘formatter_name’ is not a member of ‘int’.

Which is true: the primitive type int does not have members at all, so it does not have formatter_name member in particular.

This explains the error, which is as-prescribed by the C++ standard.


Now, you mention expecting conversion, is it because of the non-explicit constructor for Hole taking a double?

If so, this conversion would implicitly happen only if you gave a double to a "context" expecting an Hole instance.

E.g, if you changed the Foo initialization to Foo f<Hole>(43.0); or Foo f(Hole{43.0});

This is absolutely not the case in you example: you give a double to Foo constructor that is templated on the argument type, and you do not force the template type yourself. So function template type deduction kicks-in, and it exactly matches the argument type. Additionally, implementing any conversion operator would not change that fact.

Upvotes: 2

Related Questions