【问题标题】:Change constructor precedence更改构造函数优先级
【发布时间】:2011-04-19 17:54:36
【问题描述】:

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

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

}

【问题讨论】:

    标签: c++ templates constructor overload-resolution


    【解决方案1】:
    template <typename T> Variant(const T&)  // (a)
    Variant(const CustomVariant&)            // (b)
    

    调用(a)不需要转换;参数类型DerivedVariantBT = DerivedVariantB 完全匹配。

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

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

    您可以通过使用std::enable_if 来禁止使用T 派生自Variant 的模板:

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

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

    【讨论】:

    • 是的,这是标准定义的规则。问题是,有什么解决方法吗? :)
    • 哇太棒了。这是因为 SFINAE(没有为从 Variant 派生的类型定义值)?
    • @cytrinox:是的,这就是 SFINAE 所说的,这就是 enable_if 的用途。
    【解决方案2】:

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

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

    现在,可以调用采用DerivedVariantB 类型引用的构造函数,而不是模板生成的构造函数。

    【讨论】:

      猜你喜欢
      • 2015-10-07
      • 1970-01-01
      • 1970-01-01
      • 2010-11-25
      • 2012-02-24
      • 2012-11-26
      • 1970-01-01
      • 1970-01-01
      • 2021-03-06
      相关资源
      最近更新 更多