Change constructor priority

Is it possible to define a constructor for all derived types and a template constructor? I wrote this test to illustrate my problem:

#include <iostream> class Variant; class CustomVariant; class Variant { public: Variant(void) {} Variant(const Variant&) { std::cout << "ctor" << std::endl; } Variant(const CustomVariant&) { std::cout << "custom" << std::endl; } template<typename T> Variant(const T&) { std::cout << "template" << std::endl; } }; class CustomVariant : public Variant { }; class DerivedVariantA : public CustomVariant { }; class DerivedVariantB : public CustomVariant { }; int main(void) { DerivedVariantB dvb; Variant v(dvb); // expcected output: "custom" instead of "template" } 
+4
source share
2 answers
 template <typename T> Variant(const T&) // (a) Variant(const CustomVariant&) // (b) 

Calling (a) does not require any conversion; argument type DerivedVariantB , is an exact match, where T = DerivedVariantB .

A derivative conversion is required for invocation (b) . Therefore, (a) goes better with (b) .

If you call a constructor with an argument of type CustomVariant , both constructors are exact matches, so (b) is selected because, when everything else is equal, a template is preferable to a template.

You can suppress the use of a pattern where T obtained from Variant with std::enable_if :

 template<typename T> Variant(const T&, typename std::enable_if< !std::is_base_of<Variant, T>::value, void* >::type = 0) { std::cout << "template" << std::endl; } 

This makes the template incompatible when T obtained from Variant , so it will not be available during overload resolution. enable_if and is_base_of are new to C ++ in C ++ 0x, and your compiler and standard library can support them. If not, you can also find them in C ++ TR1 or Boost.TypeTraits .

+6
source

No, among the list of constructors available in the class, there is no constructor that takes an instance of type DerivedVariantB as an argument. Therefore, the called template is invoked.

 class DerivedVariantB ; // Forward Declaration class Variant { public: // ... Variant( const DerivedVariantB &obj ) { std::cout << "\n DerivedVariantB \n"; } }; 

Now you can call the constructor, which accepts a link of type DerivedVariantB instead of the created template.

0
source

All Articles