简体   繁体   English

包装为完美的转发构造函数

[英]Wrapper for perfect forwarding constructor

I want to make a wrapper for a constructor of a class B. 我想为B类的构造函数做一个包装。

Since some part of the class B is replaceable, I group each implementation of those parts into several class A. 由于类B的某些部分是可替换的,因此我将这些部分的每种实现分组为几个类A。

I use perfect forwarding to provide a default implementation of A for constructing a B. 我使用完美转发为构建B提供A的默认实现。

The problem is the wrapper doesn't work. 问题是包装器不起作用。 How to fix this? 如何解决这个问题?

Thanks. 谢谢。

The following is also at https://godbolt.org/g/AWwtbf 以下也是https://godbolt.org/g/AWwtbf

template<typename T>
class A {
public:
    A() { _x = 2; }
    int _x;
};

template<typename T, typename C=A<T> >
class B {
public:
    explicit B(T x, C&& a = A<T>())
            : _x(x), _a(a) {
    }
    T _x;
    A<T>& _a;
};

template<typename T, typename C=A<T> >
B<T, A<T>> make_b(T x, C&& c = A<T>()) {
    return B<int, A<int>>(x, c);
};

int main() {
    B<int, A<int>> b1(1);  // this works.
    auto b2 = make_b(1);  // this doesn't
}

Error: 错误:

error: cannot bind rvalue reference of type 'A<int>&&' to lvalue of type 'A<int>'

     return B<int, A<int>>(x, c);

How to perfect-forward stuff? 如何完美转发东西?

  1. Make the type of the argument a template parameter. 将参数的类型设为template参数。
  2. Accept the argument by rvalue-reference ( && ). 通过右值引用( && )接受参数。
  3. std::forward the argument. std::forward参数。

You got nr. 你得到了。 1 and 2 but forgot nr. 1和2,但忘记了nr。 3: 3:

template<typename T, typename C=A<T> >
B<T, A<T>> make_b(T x, C&& c = A<T>()) {
    return B<T, A<int>>(x, std::forward<C>(c));
};

How to avoid a dangling reference? 如何避免悬挂参考?

This code creates a dangling reference, ie a reference to an object that's already gone : 这段代码创建了一个悬空的引用,即对已经消失的对象的引用:

    explicit B(T x, C&& a = A<T>())
            : _x(x), _a(a) {
    }
    T _x;
    A<T>& _a;

Consider what happens here: a temporary A is created, the rvalue reference a is being used in an lvalue expression ( a ) so it turns into an lvalue reference and A& _a subsequently happily binds to it. 考虑一下这里发生的情况:创建了一个临时A ,在左值表达式( a )中使用了右值引用a因此它变成了左值引用,随后A& _a愉快地绑定到该值。 By the time the full-expression is finished (at the first ; ) the temporary A instance is destroyed and A& _a refers to a non-existent object. 到全表达式完成时(在第一个; ),临时A实例已被破坏,并且A& _a引用了不存在的对象。 If _a is used after that point, the behavior is undefined. 如果在此之后使用_a ,则行为未定义。

Avoid references as data members until you understand value categories , object lifetime and reference collapsing rules. 在理解值类别对象生存期引用崩溃规则之前,请避免将引用作为数据成员。

Just store A by value: 只需按值存储A

    explicit B(T x, C&& a = A<T>())
            : _x(x), _a(std::move(a)) {
    }
    T _x;
    A<T> _a;

Or instantiate A outside B and pass it as an lvalue reference: 或实例化A外的B并将其作为左值引用传递:

    explicit B(T x, C& a) : _x(x), _a(a) {}
    C& _a;

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

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