I have a template class and a friend operator* function
StereoSmp<TE> operator* (const StereoSmp<TE>& a, TE b)
I use it with TE=float but I need to multiply a StereoSmp<float> * double
I think that should be possibile because it should converts double to float automatically and works but I get the error:
no match for ‘operator*’ (operand types are ‘StereoSmp<float>’ and
‘__gnu_cxx::__alloc_traits<std::allocator<double> >::value_type {aka double}’)
deduced conflicting types for parameter ‘TE’ (‘float’ and ‘double’)
Why it doesn't convert double to float automatically? And what can I do to allow the automatic conversion between types?
Don't make your friend a template.
template<class TE>
struct StereoSmp {
friend StereoSmp operator* (const StereoSmp& a, TE b) {
return multiply( a, b ); // implement here
}
};
this is a non-template friend to each type instance of the template StereoSmp. It will consider conversions.
Template functions don't consider conversions, they simply do exact pattern matching. Overload resolution is already insane enough in C++.
Keep it simple, silly:
template<class U>
StereoSmp<TE> operator* (const StereoSmp<TE>& a, U b);
or if it applies:
StereoSmp<TE> a {/* ... */};
double b = /* ... */;
auto c = a * static_cast<float>(b);
Why it doesn't convert double to float automatically?
Because template deduction happens before possible conversions are taken into consideration. If you call a*b with a a StereoSmp<float> and b a double, template substitution will fail before a float to double conversion can be considered, and name lookup will continue, until failing short of candidates.
This process is called Template argument deduction.
Although Yakk's answer is probably the best in this particular scenario, I want to point out that you can prevent this deduction conflict and get your expected result (pass StereoSmp<float>, deduce TE as float) by making the other argument ineligible for use in deduction:
StereoSmp<TE> operator* (const StereoSmp<TE>& a, remove_reference<TE>::type b)
Related reading: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3766.html
Why it doesn't convert double to float automatically? And what can I do to allow the automatic conversion between types?
This isn't a conversion problem, it's a template parameter inference issue. Since the declaration is of the form:
StereoSmp<TE> operator* (const StereoSmp<TE>& a, TE b)
... and the operands are of type StereoSmp<float> and double, the C++ inference rules do not work, because they do not take into account that a double is convertible to a float. These rules are specified by the language specification; the reason why they don't take potential conversions into account is probably because "it would make deduction very complicated, otherwise". The rules are already complex enough!
You can of course cast your double parameter to a float and it will work fine. Also, you could make the operator* a member function of StereoSmp, or you could independently parameterise the types of the type parameters:
template <class TE, class U> StereoSmp<TE> operator* (const StereoSmp<TE>& a, U b);
Related
I am trying to use custom operators in C++ for a project I am working on. This project uses the ROCm/HIP stack (so, under the hood, the clang compiler).
Here's the error message:
src/zlatrd.cpp:359:32: error: use of overloaded operator '*' is ambiguous (with operand types 'magmaDoubleComplex' (aka 'hip_complex_number<double>') and 'float')
alpha = tau[i] * -0.5f * value;
~~~~~~ ^ ~~~~~
./include/magma_operators.h:190:1: note: candidate function
operator * (const magmaDoubleComplex a, const double s)
^
./include/magma_operators.h:183:1: note: candidate function
operator * (const magmaDoubleComplex a, const magmaDoubleComplex b)
^
./include/magma_operators.h:437:1: note: candidate function
operator * (const magmaFloatComplex a, const float s)
^
./include/magma_operators.h:430:1: note: candidate function
operator * (const magmaFloatComplex a, const magmaFloatComplex b)
^
It seems to me that it is not ambiguous; it should select the third candidate function, as the argument is a float.
Here is the type definition for the hip_complex_number template:
template <typename T>
struct hip_complex_number
{
T x, y;
template <typename U>
hip_complex_number(U a, U b)
: x(a)
, y(b)
{
}
template <typename U>
hip_complex_number(U a)
: x(a)
, y(0)
{
}
hip_complex_number()
: x(0)
, y(0)
{
}
};
I notice it has an implicit constructor that will convert a float, but I assumed that given a candidate function that matches the type exactly (not including the const modifier), that it would obviously select that function overload over those which require an implicit cast.
EDIT: Also, I know that by default C/C++ convert from float/double to each other if the function is defined in that way, so 'matches the type exactly' was definitely not the right wording.
Can someone explain why C++ thinks this is ambiguous?
EDIT: People have asked for the definition of magmaFloatComplex, which is hip_complex_number<float>
Please note that I don't know anything about the library that these types are from. I will explain the ambiguity purely based on the information in the question.
The first and third overload are ambiguous.
In the overload operator * (const magmaDoubleComplex a, const double s) a floating-point promotion from float to double is required in the second argument.
In the overload operator * (const magmaFloatComplex a, const float s) a user-defined conversion to an unrelated type from magmaDoubleComplex to magmaFloatComplex is required. This conversion is possible, because of the non-explicit converting constructor
template <typename U>
hip_complex_number(U a)
The corresponding other parameters don't need any conversion aside from potentially lvalue-to-rvalue conversions or user-defined conversion to the same type, which are considered exact match.
Exact match is better than either user-defined conversion to an unrelated type or floating-point promotion, meaning that each overload has one parameter that is better than the other one's and one that is worse than the other one's.
Overload resolution is ambiguous if not at least one overload has all parameters not worse than all other overload's parameters. Therefore the two mentioned overloads are ambiguous here.
The second overload has exact match in the first argument and requires a user-defined conversion to unrelated type in the second argument, which is again possible because of the converting constructor mentioned above. However the floating-point promotion of the first overload is considered better than a user-defined conversion to unrelated type and therefore the second overload looses against the first one in overload resolution, but would be ambiguous with the third one as well.
The fourth overload is worse than all the others, because it requires user-defined conversions to unrelated types in both parameters.
Note that if overload 3 would be selected as expect in your question, it would result in an error, because the converting constructor chosen for magmaFloatComplex will try to initialize the x member which is of type float with a magmaDoubleComplex, which (at least based on your shown code) doesn't have a conversion operator to float.
Why does the following code not compile if I remove enable_if?
template<class T, class = typename std::enable_if<
std::is_constructible<T, double,double,double>::value
>::type >
operator T() const
{
return T{x, y, z};
}
Example code:
with enable_if
http://ideone.com/nWdmJh
without enable_if + compile error
http://ideone.com/FBMamF
Without enable_if, your conversion operator exists for every type. You would get an error if attempting to instantiate the conversion operator for types that cannot be constructed from {x, y, z}, but that doesn't change the fact that the operator exists. Because it exists, the type is considered convertible to double *, and overload resolution cannot pick a best match.
Your operator T() returns a T list initialized with x,y,z. This means that the overload of DoSomething is ambiguous between the one that takes 2 vectors or the one that takes a vector and double*.
So if you cast your second argument at the call site to what type it is that you want you will tell the compiler explicitly what overload to take.
The std::enable_if basically removes the overload that is not constructible using three doubles, meaning it removes the ambiguity, and therefore it compiles.
Your vector is constructible with three doubles.
Vector(double x, double y, double z)
std::vector<std::complex<float> > c;
std::vector<float> d;
std::transform(c.begin(), c.end(), d.begin(), std::real<float>);
Why couldn't the compiler resolve the address from the overloaded function real<float>?
Which overloaded functions does the compiler mean?
Your library implementation has provided additional overloads for std::real<float>.
Why the overloads?
26.4.9 Additional overloads [cmplx.over]
1 The following function templates shall have additional overloads:
arg norm
conj proj
imag real
2 The additional overloads shall be sufficient to ensure:
If the argument has type long double, then it is effectively cast to complex<long double>.
Otherwise, if the argument has type double or an integer type, then it is effectively cast to complex<double>.
Otherwise, if the argument has type float, then it is effectively cast to complex<float>.
[...]
Solutions to problem:
You could just use a range based for ...
for (auto v : c) d.push_back(real(v));
... or pack the call to real into a functor or another function ...
struct my_caller {
template <typename T> T operator() (std::complex<T> const &c) {
return real(c);
}
};
... or use the member function ...
std::transform(c.begin(), c.end(), d.begin(), [](std::complex<T> const &c) {
return c.real();
});
IMPORTANT:
Note that you have to have enough space in the target when using transform:
std::vector<float> d (c.size());
or use a back inserter:
std::transform(c.begin(), c.end(), back_inserter(d), ...);
Otherwise you are iterating over undefined memory, yielding undefined behaviour.
§26.4.9 states that (amongst others), real shall have additional overloads, for arguments of type float, double and long double. It seems your libraray implementation made a template for these overloads, maybe like
template <typename T>
T real(T const& t)
{
return std::real(std::complex<T>{t});
}
In addition to the solutions phresnel priovided, you could explicitly tell the compiler which kind of function pointer you mean:
std::transform(c.begin(), c.end(), d.begin(), (float(*)(std::complex<float> const&))std::real<float>);
The compiler then looks for a std::real that can be converted into a function pointer of the given type and will find the correct one.
I tell you this only for completeness - I consider this explicit cast ugly and would prefer the ranged based for or transform with a lambda.
I have a function that is defined as follows:
template < class T> T doSomething(const T value, const T value2, const T value3)
{
T temp = value;
//Do stuff
return temp ;
}
in my main, I go to call it as follows:
doSomething(12.0, 23.0f, 2.0f);
I get an error saying no matching function for call doSomething(double, float, float).
I tried to used const_cast but it didn't seem to fix the issue. Any help would be appreciated.
It's not about the const, but about that T cannot be both double and float at the same time.
If you have a non-template function, one or more parameter can be promoted (or converted) to the parameter type. With a template function, the compiler will have to start by determining what the template type is supposed to be. Here it cannot decide.
Your function definition uses same type "T" for every of three arguments.
C++ is not able to deduct types in cases like this.
Please choose way to fix:
Different types for every argument
template<typename A, typename B, typename C>
A doSomething(const A& value, const B& value2, const C& value3)
{
A temp = value;
//Do stuff
return temp ;
}
Explicit template argument on call:
doSomething<int>(12.0, 23.0f, 2.0f);
Explicit type cast for argument on call:
doSomething(12.0, static_cast<double>(23.0f), static_cast<double>(2.0f));
When using a templated function, you need to supply the template parameters within angle brackets.
I.e. you need to use doSomething<float>(12.0, 23.0f, 2.0f);
Or, at least, if you don't, the compiler has to guess what T is, which means when it sees a double for the first argument it assumes you mean doSomething<double>()
When you call like this:
doSomething(12.0, 23.0f, 2.0f);
then you basically let the compiler to deduce the template argument T, from the function arguments. But in the above call, type of all arguments are not same : the first argument12.0 is double, while the rest two arguments are float (Note that f in 2.0f makes it a float, while 2.0 is a double.). Hence the problem, as the compiler is trying to find a function which accepts double, float, float as arguments. But there is no such function. And the function template cannot be deduced from the arguments, because T has to be same for all arguments.
So the solution is, let T be deduced as either double or float:
doSomething(12.0f, 23.0f, 2.0f); //all are float now
Or this:
doSomething(12.0, 23.0, 2.0); //all are double now
In the first case, T is deduced as float, and in the second case, T is deduced as double.
Alternately, you may choose not to depend on template argument deduction, by providing template argument as:
doSomething<float>(12.0, 23.0f, 2.0f);
Or this:
doSomething<double>(12.0, 23.0f, 2.0f);
Here, in the first case, the 1st argument converts into float, and in the second case, 2nd and 3rd argument convert into double.
I have a class that encapsulates some arithmetic, let's say fixed point calculations. I like the idea of overloading arithmetic operators, so I write the following:
class CFixed
{
CFixed( int );
CFixed( float );
};
CFixed operator* ( const CFixed& a, const CFixed& b )
{ ... }
It all works. I can write 3 * CFixed(0) and CFixed(3) * 10.0f. But now I realize, I can implement operator* with an integer operand much more effective. So I overload it:
CFixed operator* ( const CFixed& a, int b )
{ ... }
CFixed operator* ( int a, const CFixed& b )
{ ... }
It still works, but now CFixed(0) * 10.0f calls overloaded version, converting float to int ( and I expected it to convert float to CFixed ). Of course, I can overload a float versions as well, but it seems a combinatorial explosion of code for me. Is there any workaround (or am I designing my class wrong)? How can I tell the compiler to call overloaded version of operator* ONLY with ints?
You should overload with float type as well. Conversion from int to user-specified type (CFixed) is of lower priority than built-in floating-integral conversion to float. So the compiler will always choose function with int, unless you add function with float as well.
For more details, read 13.3 section of C++03 standard. Feel the pain.
It seems that I've lost track of it too. :-( UncleBens reports that adding float only doesn't solve the problem, as version with double should be added as well. But in any case adding several operators related to built-in types is tedious, but doesn't result in a combinatorial boost.
If you have constructors which can be invoked with just one argument, you effectively created an implicit conversion operator. In your example, wherever a CFixed is needed, both an int and a float can be passed. This is of course dangerous, because the compiler might silently generate code calling the wrong function instead of barking at you when you forgot to include some function's declaration.
Therefore a good rule of thumb says that, whenever you're writing constructors that can be called with just one argument (note that this one foo(int i, bool b = false) can be called with one argument, too, even though it takes two arguments), you should make that constructor explicit, unless you really want implicit conversion to kick in. explicit constructors are not used by the compiler for implicit conversions.
You would have to change your class to this:
class CFixed
{
explicit CFixed( int );
explicit CFixed( float );
};
I have found that there are very few exceptions to this rule. (std::string::string(const char*) is a rather famous one.)
Edit: I'm sorry, I missed the point about not allowing implicit conversions from int to float.
The only way I see to prevent this is to provide the operators for float as well.
Assuming you'd like the specialized version to be picked for any integral type (and not just int in particular, one thing you could do is provide that as a template function and use Boost.EnableIf to remove those overloads from the available overload set, if the operand is not an integral type.
#include <cstdio>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>
class CFixed
{
public:
CFixed( int ) {}
CFixed( float ) {}
};
CFixed operator* ( const CFixed& a, const CFixed& )
{ puts("General CFixed * CFixed"); return a; }
template <class T>
typename boost::enable_if<boost::is_integral<T>, CFixed>::type operator* ( const CFixed& a, T )
{ puts("CFixed * [integer type]"); return a; }
template <class T>
typename boost::enable_if<boost::is_integral<T>, CFixed>::type operator* ( T , const CFixed& b )
{ puts("[integer type] * CFixed"); return b; }
int main()
{
CFixed(0) * 10.0f;
5 * CFixed(20.4f);
3.2f * CFixed(10);
CFixed(1) * 100u;
}
Naturally, you could also use a different condition to make those overloads available only if T=int: typename boost::enable_if<boost::is_same<T, int>, CFixed>::type ...
As to designing the class, perhaps you could rely on templates more. E.g, the constructor could be a template, and again, should you need to distinguish between integral and real types, it should be possible to employ this technique.
How about making the conversion explicit?
Agree with sbi, you should definitely make your single-parameter constructors explicit.
You can avoid an explosion in the operator<> functions you write with templates, however:
template <class T>
CFixed operator* ( const CFixed& a, T b )
{ ... }
template <class T>
CFixed operator* ( T a, const CFixed& b )
{ ... }
Depending on what code is in the functions, this will only compile with types that you support converting from.