在C ++中将通用构造函数分配给成员变量时,std :: move或std :: forward [英] std::move or std::forward when assigning universal constructor to member variable in C++

查看:105
本文介绍了在C ++中将通用构造函数分配给成员变量时,std :: move或std :: forward的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下类foo1foo2

template <typename T>
struct foo1
{
    T t_;

    foo1(T&& t) :
        t_{ std::move(t) }
    {
    }
};

template <typename T>
struct foo2
{
    foo1<T> t_;

    foo2(T&& t) :
        t_{ std::forward<T>(t) }
    {
    }
};

是否总是总是foo1的构造函数表示初始化成员变量T的正确方法?即使用std::move.

Is it always the case that the constructor of foo1 represents the correct way to initialise the member variable T? i.e. by using std::move.

由于需要转发到foo1的构造函数,因此foo2的构造函数是否总是代表初始化成员变量foo1<T>的正确方法?即使用std::forward.

Is it always the case that the constructor of foo2 represents the correct way to initialise the member variable foo1<T> due to needing to forward to foo1's constructor? i.e. by using std::forward.

更新

对于使用std::movefoo1,以下示例失败:

The following example fails for foo1 using std::move:

template <typename T>
foo1<T> make_foo1(T&& t)
{
    return{ std::forward<T>(t) };
}

struct bah {};

int main()
{
    bah b;

    make_foo1(b); // compiler error as std::move cannot be used on reference

    return EXIT_SUCCESS;
}

这是一个问题,因为我希望T既是引用类型又是值类型.

Which is a problem as I want T to be both a reference type and a value type.

推荐答案

这些示例都没有使用通用引用(转发引用,现在称为它们).

Neither of these examples use universal references (forwarding references, as they are now called).

仅在存在类型推导的情况下形成转发引用,但在foo1foo2的构造函数中未推导T&&,因此它只是一个右值引用.

Forwarding references are only formed in the presence of type deduction, but T&& in the constructors for foo1 and foo2 is not deduced, so it's just an rvalue reference.

由于两者都是右值引用,因此您都应在两者上均使用std::move.

Since both are rvalue references, you should use std::move on both.

如果要使用转发引用,则应使构造函数具有推导的模板参数:

If you want to use forwarding references, you should make the constructors have a deduced template argument:

template <typename T>
struct foo1
{
    T t_;

    template <typename U>
    foo1(U&& u) :
        t_{ std::forward<U>(u) }
    {
    }
};

template <typename T>
struct foo2
{
    foo1<T> t_;

    template <typename U>
    foo2(U&& u) :
        t_{ std::forward<U>(u) }
    {
    }
};

在这种情况下,您不应在foo1中使用std::move,因为客户端代码可能会传递一个左值,并使该对象无声地失效:

You should not use std::move in foo1 in this case, as client code could pass an lvalue and have the object invalidated silently:

std::vector<int> v {0,1,2};
foo1<std::vector<int>> foo = v;
std::cout << v[2]; //yay, undefined behaviour

一种更简单的方法是按值无条件地将std::move放入存储中:

A simpler approach would be to take by value and unconditionally std::move into the storage:

template <typename T>
struct foo1
{
    T t_;

    foo1(T t) :
        t_{ std::move(t) }
    {
    }
};

template <typename T>
struct foo2
{
    foo1<T> t_;

    foo2(T t) :
        t_{ std::move(t) }
    {
    }
};

对于完美的转发版本:

  • 传递的左值->一本
  • 传递的右值->一招

对于按值传递和移动版本:

For the pass by value and move version:

  • 传递的左值->一份,一招
  • 传递的右值->两步走

请考虑该代码的性能要求以及需要更改和维护的代码量,然后基于此选择一个选项.

Consider how performant this code needs to be and how much it'll need to be changed and maintained, and choose an option based on that.

这篇关于在C ++中将通用构造函数分配给成员变量时,std :: move或std :: forward的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆