Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't my templated function promote 'int' to 'T', where 'T' = 'double'?

Tags:

I have a class templated with typename T. It contains a function,

template <typename T, size_t a> myClass<T,a> operator+(myClass<T,a> lhs, const T& rhs) {     return lhs += rhs; }  myClass<T,a> myClass<T,a>::operator+=(const T& rhs) {     // Do addition, depends on 'a'.     return *this; } 

When I call this with, for example

myClass<double, 2> myObj_double_2(constructor args); myObj_double_2 = myObj_double_2 + 5.2; 

I have no problem.

If I however call

myObj_double_2 = myObj_double_2 + 5; 

Then the compiler gives me a message like - No match for 'operator+' (operand types are 'myClass<double, 2ul>' and 'int'). Candidates are ... note: deduced conflicting types for parameter 'const T' ('double' and 'int').

Can I write the code in some way to allow additional types to be passed that have a conversion to T (since, for example, double(5) is a valid constructor call)?

like image 363
chrisb2244 Avatar asked Oct 05 '15 08:10

chrisb2244


People also ask

What is the difference between template Typename T and template T?

what's the difference between template <typename T> and template <class T>? Nothing actually. typename is a designated keyword for this purpose but class is supported for backwards compatibility and historical reasons (before typename keyword was added).

What is a templated function C++?

Function templates are special functions that can operate with generic types. This allows us to create a function template whose functionality can be adapted to more than one type or class without repeating the entire code for each type. In C++ this can be achieved using template parameters.

Which entities can be templated C++?

A templated entity (or, in some sources, "temploid") is any entity that is defined (or, for a lambda-expression, created) within a template definition. All of the following are templated entities: a class/function/variable (since C++14) template.

How will you restrict the template for a specific datatype?

There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.


2 Answers

When you are using template argument deduction, all deductions for one template parameter must have the same result.

In your case, the two deductions for T produce double and int, which are not the same, and so deduction fails.

What you can do is only use one function argument for template argument deduction, and make the other one undeduced:

template <typename T, std::size_t A> void foo(myClass<T, A> arg1, typename std::common_type<T>::type arg2); //                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Note that std::common_type<T>::type is essentially just T, but because the type of arg2 is now a dependent type (its name appears to the right of a ::), it is not deduced. Therefore, only the first argument takes part in deduction and produces T = double unambiguously, and then the second function parameter just has type double, and the usual conversions take place.

As a rule of thumb, template argument deduction does not cross ::.

like image 142
Kerrek SB Avatar answered Oct 12 '22 15:10

Kerrek SB


The compiler on overload resolution fails to find a right candidate for operator+ because T is already being deducted to double and literal 5 is an integer. Solution:

template <typename T1, typename T2, size_t a> myClass<T1,a> operator+(myClass<T1,a> lhs, const T2& rhs) {     return lhs += T1(rhs); } 
like image 32
101010 Avatar answered Oct 12 '22 15:10

101010