【问题标题】:Derive from template constructor of template base class派生自模板基类的模板构造函数
【发布时间】:2014-10-24 18:11:47
【问题描述】:

只是好奇,是否有可能从模板类继承并在派生类的构造函数中调用基类的构造函数,该基类也是模板化的并且没有参数来推断其类型?

template<typename T>
struct Base {
    template<typename D>
    Base() {                // no argument of type D to infer from
        static_assert(std::is_same<T,D>::value, "");
    }
};

struct Derived : Base<int> {
    Derived()  : Base<int>::Base<int>() {} // is there a way to write it correctly?
};

在我的特殊情况下,我可以用模板方法替换模板构造函数,但这仍然是一个关于语言灵活性的有趣问题。

【问题讨论】:

  • 不可能为构造函数显式指定模板参数。所以不,你不能那样做。
  • 看起来很偏执(确保派生类正确使用基类)
  • 如果您认为 Base 类使用编译时信息来为其构造选择不同的操作,则不是这样。

标签: c++ templates inheritance c++11


【解决方案1】:

C++ 标准对此有何评论(第 14.8.1 节):

[注意:因为显式模板实参列表跟在函数模板名之后,并且因为转换成员函数模板和构造函数成员函数模板是在不使用函数名的情况下调用的,所以没有办法为这些提供显式模板实参列表功能模板。 ——尾注]

这是一个注释,而不是一个规则,因为它实际上是另外两个规则的结果,一个在同一部分:

可以在引用函数模板特化时指定模板参数,方法是使用模板参数列表限定函数模板名称,就像在使用类模板特化时指定模板参数一样。

从 12.1 开始

构造函数没有名字。

【讨论】:

    【解决方案2】:

    构造函数模板的模板参数必须从它们的参数中推导出来,不可能为构造函数显式指定模板参数。

    因此,让Base 采用一个虚拟参数来推断参数:

    template <typename T>
    struct dummy { }; // to prevent instantiation of T
    
    template <typename T>
    struct Base
    {
        template <typename D>
        Base(dummy<D>)
        {
            static_assert(std::is_same<T, D>::value, "");
        }
    };
    
    struct Derived : Base<int>
    {
        Derived() : Base<int>(dummy<int>{}) { }
    };
    

    【讨论】:

    • 哪个是标签调度(避免虚拟调度)
    • 谢谢,在我的特殊情况下,这并不方便,因为 Base 构造函数已经具有可变参数并且 D 也是可变参数 :) 如果它为它带来额外的价值,我可以更新问题
    • @Anton 然后使dummy 可变参数。
    • @DieterLücking 您指的是术语吗?那么这个叫做“标签调度”吗?
    • @Anton 让dummy 也成为可变参数难道没有帮助吗?
    【解决方案3】:

    问题的表述方式看起来像是一种荒谬的偏执狂。

    想想简单的类:

    class Base 
    {
    public:
        Base() {}
    };
    
    class Derived: public Base
    {
    public:
        Derived() //< default ctor
          :Base  //< this is the Base type
               () //< this selects what ctor to call
        {}
    };
    

    请注意,您调用:Base(),它解析为Base::Base(),而不是:Base::Base()

    现在,通过模板化Base::Base(),您实际上是在尝试承认 Base 可以有许多不同的默认 ctor(使用 ())。这是对“默认”概念本身的无意义尊重。

    即使 Base 本身不是模板,这也是不可能的:

    class Base
    {
    public:
       template<class T>
       Base() {} //< are there infinite way to default construct Base ?!?
    };
    
    Base b; //< so how is b constructed ?
    

    使用 varadics 只会让事情变得明显不同:

    template<class T>
    class Base
    {
    public:
        template<class... S>
        Base(S&&... s) { /* something to do */ }
    };
    
    class Derived: public Base<int>
    {
    public:
       template<class... S>
       Derived(S&&... s) //< Derived varadicly initialized
             :Base //< base type ...
             (std::forward<S>(s)...) //< ... to initialize with what
       {}
    };
    

    请注意,如果s 为空,您实际上是从Derived()::Derived() 调用Base::Base(),模板化为&lt;&gt;(无参数)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-09
      • 2014-09-23
      • 2021-04-20
      • 1970-01-01
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多