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?
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.
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