Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rules for implicit conversion of template arguments

If you overload a function and then call it with an argument that perfectly matches one of the overloads

int f(int){return 3;}
int f(bool){return 4;}
...        //inside main()
f(1);      //Calls f(int)

the compiler simply chooses this (perfect) match before attempting any implicit conversions. However I've been trying to overload a function tempĺate as in

template <bool veracity>
int f(){return 1;}

template <int amount>
int f(){return 2;}

...        //inside main()
f<1>();

but the compiler keeps complainning about ambiguous call to the overloaded f(), stating it could be either f<true>() or f<1>(). Shouldn't the compiler just choose the perfect match, instead of trying to convert 1 to true ?

I was under the impression that implicit conversion for template arguments was actually more restrictive than implicit conversion of function arguments. Is there a way to get around this problem?

like image 632
Malabarba Avatar asked Apr 05 '12 15:04

Malabarba


2 Answers

The argument you're supplying isn't a type, it's a value, so the rules are a bit different -- you need to apply the rules for non-type arguments. For non-type arguments, implicit conversions are allowed. §14.3.2/5:

The following conversions are performed on each expression used as a non-type template-argument. If a non-type template-argument cannot be converted to the type of the corresponding template-parameter then the program is ill-formed.

— For a non-type template-parameter of integral or enumeration type, conversions permitted in a converted constant expression (5.19) are applied.

In C++03, the wording is marginally different, but the effect essentially identical (also §14.3.2/5):

— for a non-type template-parameter of integral or enumeration type, integral promotions (4.5) and integral conversions (4.7) are applied.

Either way, since 1 is both an int and implicitly convertible to a bool, your call is ambiguous.

like image 191
Jerry Coffin Avatar answered Sep 18 '22 12:09

Jerry Coffin


Since this isn't a compiler bug but a language feature (see this answer), you have to find a work around.

Either you have to rename your functions or you can use this hack:

template <typename T> struct F;

template<> struct F<bool> {
  template <bool veracity>
  static int f(){return 1;}
};

template<> struct F<int> {
  template <int amount>
  static int f(){return 2;}
};

template <typename T, T value>
int f() { return F<T>::template f<value>(); }

// inside main():
std::cout << f<int,  2>() << '\n'; // prints 2
std::cout << f<bool, 2>() << '\n'; // prints 1
like image 32
ipc Avatar answered Sep 19 '22 12:09

ipc