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

时间:2018-04-13 15:55:08

标签: c++ constructor wrapper perfect-forwarding

我想为B类的构造函数创建一个包装器。

由于B类的某些部分是可替换的,因此我将这些部分的每个实现分组为几个A类。

我使用完美转发来提供A的默认实现来构造B。

问题是包装器不起作用。如何解决这个问题?

感谢。

以下内容也在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: cannot bind rvalue reference of type 'A<int>&&' to lvalue of type 'A<int>'

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

1 个答案:

答案 0 :(得分:2)

如何完美转发内容?

  1. 将参数类型设为template参数。
  2. 通过rvalue-reference(&&)接受参数。
  3. std::forward论证。
  4. 你得到了。 1和2,但忘了nr。 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));
    };
    

    如何避免悬空参考?

    此代码创建一个悬空引用,即对已经gone的对象的引用:

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

    考虑这里发生的事情:创建一个临时A,在左值表达式(a)中使用右值引用a,因此它变为左值引用和{{ 1}}随后愉快地与它结合。当完整表达式完成时(在第一个A& _a),临时;实例被销毁,A引用不存在的对象。如果在该点之后使用A& _a,则行为未定义。

    在您理解value categoriesobject lifetimereference collapsing规则之前,请避免引用为数据成员。

    只需按值存储_a

    A

    或在 explicit B(T x, C&& a = A<T>()) : _x(x), _a(std::move(a)) { } T _x; A<T> _a; 之外实例化A并将其作为左值参考传递:

    B