更改构造函数优先级

cyt*_*nox 4 c++ templates constructor overload-resolution

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

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

}
Run Code Online (Sandbox Code Playgroud)

Jam*_*lis 6

template <typename T> Variant(const T&)  // (a)
Variant(const CustomVariant&)            // (b)
Run Code Online (Sandbox Code Playgroud)

呼叫(a)不需要转换; 参数类型,DerivedVariantB是完全匹配的地方T = DerivedVariantB.

调用(b)需要派生到基础的转换.因此,(a)是比(b)更好的匹配.

如果使用类型的参数调用构造函数CustomVariant,则两个构造函数都是完全匹配,因此选择(b)因为其他条件相同,所以非模板优先于模板.

您可以通过使用以下内容来禁止使用模板T来源:Variantstd::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;
}
Run Code Online (Sandbox Code Playgroud)

这使得模板在T派生时不可实例化Variant,因此在重载解析期间不可用. enable_if并且is_base_of是C++ 0x中C++的新手,您的编译器和标准库可能会支持它们.如果没有,您也可以在C++ TR1或Boost.TypeTraits中找到它们.