继承构造函数与转发

时间:2015-01-14 19:48:27

标签: c++ c++11 inheriting-constructors

C ++ 11允许继承构造函数,从而可以避免大量的样板,尤其是类似于包装类的东西。但是,似乎您已经可以单独使用可变参数模板来实现此功能。

class B
{
public:
 B(int){//do something}
 B(int, char){//do something}
};

使用继承构造函数:

class D : public B
{
public:
 using B::B; 
};

使用可变参数模板并转发:

class D : public B
{
public:
 template <typename...Args>
 D(Args&&... args) : B(std::forward<Args>(args)...)
 {
 }
};

虽然一致性(对using采用相同的方式处理构造函数和方法)和易用性是将继承的构造函数引入语言的非常好的理由,但是有任何其他原因导致第一个解决方案应该优先于第二?我发现讨论继承构造函数的CWG文档(N1890N1898)只是注意以下内容并继续:

  

仅仅是历史事故阻止使用它来为构造函数工作   至于普通的会员功能。有一个构造函数被称为“ctor”或“构造函数”   这不会被他们班级的名字所引用,而是可行的。我们   建议将此作为继承构造函数的机制。

3 个答案:

答案 0 :(得分:4)

最重要的原因是完美的转发并不完美。简单案例:

struct B {
    B(int* ) { .. }
};

现在考虑:

D d{0};

如果我们继承构造函数,这很好用。如果我们完美转发,我们会尝试构建B(int ),因为0推导为int,这是一个不存在的构造函数。失败!

其他失败案例包括支持初始化,仅声明的静态const数据成员,重载函数和位域。

答案 1 :(得分:3)

完美的转发并不完美。特别是,0作为实际参数减少到int而不是表示一般的null值。因此,如果构造函数采用指针参数,0将作为继承构造函数的实际参数,但不适用于转发。

我认为我曾经提到的另一个原因是,当问题(我们真的需要继承构造函数)被播出时,继承构造函数是一个简单的符号,用于概念上简单的事情,用于简单的上下文中类。在C ++中有足够的强制复杂性和强制样板。

答案 2 :(得分:2)

维护问题(编译器错误)可能导致使用&#39;

的偏好
struct Base
{
    Base(int) {}
};

struct Derived : public Base
{
    using Base::Base;
};

struct DerivedTemplate : Base
{
    template <typename...Args>
    DerivedTemplate(Args&&... args)
    : Base(std::forward<Args>(args)...)
    {}
};

int main()
{
    // error: no matching function for call to ‘Derived::Derived(int, int)’
    Derived d(1, 2);

    // In instantiation of ‘DerivedTemplate::DerivedTemplate(Args&& ...) [with Args = {int, int}]’:
    // required from here
    // error: no matching function for call to ‘Base::Base(int, int)’
    DerivedTemplate dt(1, 2);
}

此外,每个模板实例化都是一个不同的构造函数(使用时不会相乘)