简体   繁体   English

继承构造函数与转发

[英]Inheriting constructors vs forwarding

C++11 allows inheriting constructors making it possible to avoid a lot of boilerplate, especially with something like a wrapper class. C ++ 11允许继承构造函数,从而可以避免大量的样板,尤其是类似于包装类的东西。 However, it seems like you could already achieve this functionality with variadic templates alone. 但是,似乎您已经可以使用可变参数模板实现此功能。

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

Using inheriting constructors: 使用继承构造函数:

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

Using variadic templates and forward: 使用可变参数模板并转发:

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

While consistency(treat constructors and methods the same way for using ) and ease of use are very good reasons to bring inherited constructors into the language, is there any other reason why the first solution should be preferred to the second? 虽然一致性(对待构造函数和方法的相同方式using )和易用性很好的理由把继承构造成的语言,还有没有其他原因的第一个解决方案应首选第二? Both the CWG documents( N1890 and N1898 ) I found discussing inheriting constructors simply note the following and move on: 我发现讨论继承构造函数的CWG文档( N1890N1898 )只是注意以下内容并继续:

Little more than a historical accident prevents using this to work for a constructor as well as for an ordinary member function. 仅仅是一个历史事故阻止使用它来为构造函数和普通成员函数工作。 Had a constructor been called “ctor” or “constructor” rather than being referred to by the name of their class, this would have worked. 如果构造函数被称为“ctor”或“构造函数”而不是被其类的名称引用,那么这将起作用。 We propose this as the mechanism for inheriting constructors. 我们建议将其作为继承构造函数的机制。

The big reason is that perfect forwarding isn't perfect. 最重要的原因是完美转发并不完美。 Simple case: 简单案例:

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

Now consider: 现在考虑:

D d{0};

If we inherit the constructor, this works fine. 如果我们继承构造函数,这很好。 If we perfect-forward, we would try to construct B(int ) , since 0 deduces as int , which is a constructor that doesn't exist. 如果我们完美转发,我们将尝试构造B(int ) ,因为0推导为int ,这是一个不存在的构造函数。 Failure! 失败!

Other failure cases include braced initialization, declaration-only static const data members, overloaded functions, and bitfields. 其他故障情况包括支撑初始化,仅声明的静态const数据成员,重载函数和位域。

Perfect forwarding isn't quite perfect. 完美转发并不完美。 In particular, 0 as actual argument reduces to int instead of denoting a general nullvalue. 特别是,0作为实际参数减少为int而不是表示一般的nullvalue。 So with a constructor taking a pointer argument, 0 will work as actual argument for an inherited constructor, but not for the forwarding. 因此,对于构造函数采用指针参数, 0将作为继承构造函数的实际参数,但不用于转发。

Another reason that I think I mentioned at one time when the question (do we really need inheriting constructors) was aired, is that inheriting constructors is a simple notation for a conceptually simple thing, to be used in the context of a simple class. 我认为我曾经提到的另一个原因是,问题(我们真的需要继承构造函数)是否被播出,继承构造函数是一个简单的符号,用于概念上简单的事情,用于简单类的上下文中。 There is enough forced complexity and forced boilerplate in C++. 在C ++中有足够的强制复杂性和强制样板。

Maintenance issues (compiler errors) might lead to preference of 'using': 维护问题(编译器错误)可能会导致'使用'的偏好:

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

Also, each template instantiation is a different constructor (while using does not multiply) 此外,每个模板实例化都是一个不同的构造函数(使用时不会相乘)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM