C ++ variation patterns and implicit conversions

I am trying to understand how C ++ compilers allow implicit conversions when there is a variable template constructor and a conversion operator. The following is a minimal example to illustrate:

When I write:

#include <iostream> class A { public: A () {} template<typename...tTypes> A (tTypes...pArgs) { std::cout << __PRETTY_FUNCTION__ << std::endl; } }; class B { public: operator A () const { std::cout << __PRETTY_FUNCTION__ << std::endl; return A(); } }; int main() { B b; A a = b; } 

When I start, I get this output: B::operator A() const . Therefore, it uses a conversion operator (as I expected). Example in http://ideone.com/ZZ2uBz mode

But when A is a template, the result is different:

 #include <iostream> template<typename tType> class A { public: A () {} template<typename...tTypes> A (tTypes...pArgs) { std::cout << __PRETTY_FUNCTION__ << std::endl; } }; class B { public: template<typename tType> operator A<tType> () const { std::cout << __PRETTY_FUNCTION__ << std::endl; return A<tType>(); } }; int main() { B b; A<float> a = b; } 

When I run this program, I get this output: A<tType>::A(tTypes ...) [with tTypes = {B}; tType = float] A<tType>::A(tTypes ...) [with tTypes = {B}; tType = float] . Thus, instead of the conversion operator to B , the variable constructor A . Example in http://ideone.com/u9Rxuh mode

Can someone explain to me why the difference? Should the conversion operator take precedence over the constructor?

I know that I could explicitly call the conversion operator ( A<float> a = b.operator A<float>(); ), but this is not what I want.

+5
source share
1 answer

It seems to me that the conversion is ambiguous, and other compilers fail as expected (or at least that was my expectation). An example is the result of using clang .

To fix this problem, you can make the constructor or conversion operator explicit.
Use this as an example:

 template<typename tType> class A { public: A () {} template<typename...tTypes> explicit A (tTypes...pArgs) { /* ... */ } }; 

Or that:

 class B { public: template<typename tType> explicit operator A<tType> () const { return A<tType>(); } }; 
+2
source

Source: https://habr.com/ru/post/1264981/


All Articles