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)?
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).
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.
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.
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.
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 ::
.
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); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With