2011-04-19 52 views
4

是否可以为所有派生类型和模板构造函数定义构造函数? 我写这个的测试用例来说明我的问题:更改构造函数优先

#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" 

} 

回答

6
template <typename T> Variant(const T&) // (a) 
Variant(const CustomVariant&)   // (b) 

无需转换调用(一);参数类型DerivedVariantB完全匹配,其中T = DerivedVariantB

要求调用(b)需要导出到基准的转换。因此,(a)(b)更好匹配。

如果你调用与CustomVariant类型的参数的构造,这两个构造函数是完全匹配,因此(B)选择,因为这里的一切是平等的,非模板优于模板。

可以禁止使用其中TVariant使用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; 
} 

这使得模板时TVariant衍生没有实例化,所以它不会是重载解析过程中可用。 enable_ifis_base_of是C++ 0x中的新增功能,您的编译器和标准库可能会支持它们。如果没有,您也可以在C++ TR1或Boost.TypeTraits中找到它们。

+0

是的,那是标准定义的规则。问题是,有没有解决方法? :) – cytrinox 2011-04-19 18:10:57

+0

有;我刚刚用一个例子更新了我的答案。 – 2011-04-19 18:11:18

+0

太好了。这是因为SFINAE(价值没有定义从派生类型派生)? – cytrinox 2011-04-19 18:20:56

0

不,在类的可用构造函数列表中没有构造函数将DerivedVariantB类型的实例作为参数。因此生成的模板被调用。现在

class DerivedVariantB ; // Forward Declaration 

class Variant 
{ 
    public: 
    // ... 

    Variant(const DerivedVariantB &obj) 
    { 
     std::cout << "\n DerivedVariantB \n"; 
    } 
}; 

,它可能调用了DerivedVariantB类型,而不是产生一个模板的参考构造函数。