Reputation: 629
I am using a templated function and a non-templated one. Code is given below
#include <iostream>
using namespace std;
int maxOfTwo1(int a,int b)
{
return a>b?a:b;
}
template<class T>
T maxOfTwo(T a,T b)
{
return a>b?a:b;
}
int main()
{
cout<<maxOfTwo1(3,6.3);//works fine
cout<<maxOfTwo(3,6.3);//gives error
}
In first function 6.3
is getting converted to 6
, but can anyone explain why it doesn't happen in second function also? Second function works also the same just having template.
Upvotes: 2
Views: 436
Reputation: 158449
In your first case the type of the parameters are known (int) and the arguments are converted to that type (int), which is well-formed.
In your second case the compiler must deduce T but it ends with conflicting deductions and therefore it fails.
We can see this from [temp.deduct.type]p2 which says (emphasis mine):
In some cases, the deduction is done using a single set of types P and A, in other cases, there will be a set of corresponding types P and A. Type deduction is done independently for each P/A pair, and the deduced template argument values are then combined. If type deduction cannot be done for any P/A pair, or if for any pair the deduction leads to more than one possible set of deduced values, or if different pairs yield different deduced values, or if any template argument remains neither deduced nor explicitly specified, template argument deduction fails.
The definitions of P and A can be found in [temp.deduct.call]p1:
Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below. If removing references and cv-qualifiers from P gives std::initializer_list for some P' and the argument is an initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context ([temp.deduct.type]).
max66 gave some possible solutions, i.e. using different template parameters combined with common_type
.
Upvotes: 1
Reputation: 66190
Deduction conflict.
Given
template<class T>
T maxOfTwo(T a,T b)
{
return a>b?a:b;
}
If you call maxOfTwo(3,6.3)
, the first value is a int
; the second one is a float
.
The compiler must deduce a single T
type and don't know if select int
or float
.
The case of maxOfTwo1()
is different because the type of argument is fixed to int
and the compiler has just to convert the float
value to a int
value.
If you can use at least C++14, you can solve using two template types and a returning auto
type
template <typename T1, typename T2>
auto maxOfTwo (T1 a, T2 b)
{ return a>b?a:b; }
In C++11 is a little more verbose and less elegant
template <typename T1, typename T2>
auto maxOfTwo (T1 a, T2 b) -> decltype( a>b ? a : b )
{ return a>b?a:b; }
or you can use std::common_type
(as suggested by Yakk)
template <typename T1, typename T2>
typename std::common_type<T1, T2>::type maxOfTwo (T1 a, T2 b)
{ return a>b?a:b; }
Otherwise you can explicit the correct type calling the function
maxOfTwo<int>(3, 6.3);
Upvotes: 3