派生自模板基类的模板构造函数

Derive from template constructor of template base class

本文关键字:构造函数 基类 派生      更新时间:2023-10-16

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

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

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

C++标准对此有何规定(第14.8.1节):

[注意:由于显式模板参数列表跟随函数模板名称,并且由于转换成员函数模板和构造函数成员函数模板是在不使用函数名称的情况下调用的,因此无法为这些函数模板提供显式模板参数列表。--end Note]

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

当引用函数模板专用化时,可以通过用模板参数列表限定函数模板名称来指定模板参数,方法与使用类模板专用化指定模板参数相同。

和12.1

构造函数没有名称。

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

因此,让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>{}) { }
};

通过这个问题的表述方式,它看起来像是一种荒谬的偏执狂。

想想普通类:

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(),用<>(无参数)临时化