Why does this not compile without enable_if? - c++

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)

Related

C++ "error: use of overloaded operator '*' is ambiguous" with seemingly only one match

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 argument conversion is not considered when calling a templated function?

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);

Are implicit conversions allowed with std::tie?

In c++11, are implicit conversions allowed with std::tie?
The following code compiles and runs but I'm not sure exactly what's going on behind the scenes or if this is safe.
std::tuple<float,float> foo() { return std::make_tuple(0,0); }
double a, b;
std::tie(a,b) = foo(); // a and b are doubles but foo() returns floats
What happens is the template version of tuple's move-assignment operator is used
template< class... UTypes >
tuple& operator=(tuple<UTypes...>&& other );
which move-assigns individual tuple members one by one using their own move-assignment semantics. If the corresponding members are implicitly convertible - they get implicitly converted.
This is basically a natural extension of similar functionality in std::pair, which we've been enjoying for a long while already.

resolve address from overloaded function std::real<float>

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.

What is better to use for automatic return types: decltype or std::common_type<>::type (if possible)?

As answer to my last question it was suggested to use, when possible, std::common_type<X,Y>::type in the declaration of automatic return types instead of my original decltype(). However, doing so I ran into problems (using gcc 4.7.0). Consider the following simple code
template<typename> class A;
template<typename X> class A {
X a[3];
template <typename> friend class A;
public:
A(X a0, X a1, X a2) { a[0]=a0; a[1]=a1; a[2]=a2; }
X operator[](int i) const { return a[i]; }
X operator*(A const&y) const // multiplication 0: dot product with self
{ return a[0]*y[0] + a[1]*y[1] + a[2]*y[2]; }
template<typename Y>
auto operator*(A<Y> const&y) const -> // multiplication 1: dot product with A<Y>
#ifdef USE_DECLTYPE
decltype((*this)[0]*y[0])
#else
typename std::common_type<X,Y>::type
#endif
{ return a[0]*y[0] + a[1]*y[1] + a[2]*y[2]; }
template<typename Y>
auto operator*(Y s) const -> // multiplication 2: with scalar
#ifdef USE_DECLTYPE
A<decltype((*this)[0]*s)>
#else
A<typename std::common_type<X,Y>::type>
#endif
{ return A<decltype((*this)[0]*s)>(s*a[0],s*a[1],s*a[2]); }
};
int main()
{
A<double> x(1.2,2.0,-0.4), y(0.2,4.4,5.0);
A<double> z = x*4;
auto dot = x*y; // <--
std::cout<<" x*4="<<z[0]<<' '<<z[1]<<' '<<z[2]<<'\n'
<<" x*y="<<dot<<'\n';
}
when USE_DECLTYPE is #defined, the code compiles and runs fine with gcc 4.7.0. But otherwise, the line indicated in main() calls the multiplaction 2, which seems weird if not wrong. Could this possibly be a consequence/side effect of using std::common_type or is it a bug with gcc?
I always thought that the return type has no bearing on which of a multitude of fitting template functions is chosen...
The suggestion to use common_type is bogus.
The problem using decltype you had in your other question was simply a GCC bug.
The problem you have in this question when using common_type is because std::common_type<X, Y>::type tells you the type that you would get from the expression:
condition ? std::declval<X>() : std::declval<Y>()
i.e. what type an X and a Y can both be converted to.
In general that has absolutely nothing to do with the result of x * y, if X and Y have an overloaded operator* that returns a completely different type.
In your specific case, you have the expression x*y where both variables are type A<double>. Overload resolution tries to check each overloaded operator* to see if it's valid. As part of overload resolution it instantiates this member function template:
template<typename Y>
auto operator*(Y s) const ->
A<typename std::common_type<X,Y>::type>;
With A<double> substituted for the template parameter Y. That tries to instantiate common_type<double, A<double>> which is not valid, because the expression
condition ? std::declval<double>() : std::declval< A<double> >()
is not valid, because you cannot convert A<double> to double or vice versa, or to any other common type.
The error doesn't happen because that overloaded operator* is called, it happens because the template must be instantiated in order to decide which operator should be called, and the act of instantiating it causes the error. The compiler never gets a far as deciding which operator to call, the error stops it before it gets that far.
So, as I said, the suggestion to use common_type is bogus, it prevents SFINAE from disabling the member function templates that don't match the argument types (formally, SFINAE doesn't work here because the substitution error happens outside the "immediate context" of the template, i.e. it happens inside the definition of common_type not in the function signature, where SFINAE applies.)
It's permitted to specialize std::common_type so it knows about types without implicit conversions, so you could specialize it so that common_type<double, A<double>>::type is valid and produces the type double, like so:
namespace std {
template<typename T>
struct common_type<T, A<T>> { typedef T type; };
}
Doing so would be a very bad idea! What common_type is supposed to give is the answer to "what type can both these types safely be converted to?". The specialization above subverts it to give the answer to "what is the result of multiplying these types?" which is a completely different question! It would be as foolish as specializing is_integral<std::string> to be true.
If you want the answer to "what is the type of a general expression such as expr ?" then use decltype(expr), that's what it's for!