右值引用和构造函数参数
rvalue references and constructor arguments
让我们考虑一个简单的类
template< typename T >
class Wrapper {
public:
// Constructors?
private:
T wrapped;
};
它应该使用什么构造函数才能有效?
在 C++0x 之前,将有一个构造函数,它采用:
- 常量引用 (
T const&
( - 如果类型T
是 "重", - 或值 (
T
( - 如果类型T
是 "light"。
确定T
型是"重"还是"轻"并不容易。
人们可以假设只有内置类型(ints/floats/...(是"轻量级"的。但这并不完全正确,因为我们自己的Wrapper<int>
很可能也应该被视为"轻型"类型。
像boost::call_traits
这样的库提供了一些方法来克服这个困难,允许类型创建者将类型标记为"轻量级"(通过提供适当的call_traits
专用化(。否则将被视为"重"。似乎可以接受。
但是C++0x使情况变得更糟。因为现在你也有右值引用(T&&
(,它允许有效地采取(一些("重"物体。
正因为如此,现在你必须在以下方面做出选择:
- 只是常量引用(
T const&
( - 如果类型T
是"重"并且不支持移动语义(因为要么没有 - 就像大型 POD 一样 - 要么没有编写并且您对此没有影响(, - 常量引用(
T const&
(和右值引用(T&&
( - 如果类型T
是"重"并且确实支持移动语义, - 只是值 (
T
( - 如果类型T
是"轻"的,或者如果它是"重的"但支持移动语义(即使进行了复制,它也不会打扰使用,因为否则我们将不得不从T const&
复制自己......
仍然不容易分辨哪些类型是"重的",哪些是"轻的"(如前所述(。但是现在你也无法判断类型 T
是否支持移动语义(或者你是?
一旦包装多个值,这变得更加烦人,因为可能的构造函数重载的数量呈指数级增长。
这个问题有什么解决办法吗?
我虽然有一些用于转发(完美转发(参数的模板构造函数,但我不确定这是否会按预期工作。它还允许提供不同类型的值,这些值将转发给构造函数T
。这可能被视为一项功能,但并非必须如此。
相反,由于通用引用,C++11 使它更容易:
template <typename T> struct Wrapper
{
T value;
template <typename U> Wrapper(U && u)
: value(std::forward<U>(u))
{ }
};
作为一个额外的好处,你应该添加一个默认的第二个参数,该参数只存在于T
可以从U
构造时,这样就不会让你的类本身看起来可以从不匹配的类型构造。并使其变频:
template <typename ...Args>
Wrapper(Args &&... args,
typename std::enable_if<std::is_constructible<T, Args...>::value, int>::type = 0)
: value(std::forward<Args>(args)...)
{ }
确保#include <utility>
forward
和#include <type_traits>
特征。
如果你无论如何都要复制你的T
,最好按值传递参数,让编译器弄清楚复制。无论你做什么,无论如何都会有一个副本。
template< typename T >
class Wrapper {
public:
Wrapper(T value) : wrapped(std::move(value))
{ }
private:
T wrapped;
};
请参阅想要速度?通过戴夫·亚伯拉罕斯的值。
- 将成员函数作为构造函数参数调用时出错 "Variable is not a type name"
- 在按值调用 (c++) 中转发构造函数参数
- 如何使用 swig 修改类构造函数以保留对其中一个构造函数参数的引用?
- 如何在构造函数参数中初始化"std::set"?
- 何时应在构造函数参数中使用 const C++?
- 使用模板化结构作为构造函数参数
- 使用 lambda 作为构造函数参数是否需要C++ 17?
- 如何使输入文本文件成为构造函数参数?c++
- shared_ptr构造函数参数是否应按值传递
- 是否允许使用初始值设定项列表将const数组引用实例化为构造函数参数
- 复制构造函数参数为0
- 用作成员构造函数参数的函数的求值顺序
- 结构中的默认成员值或默认构造函数参数
- C++将引用成员绑定到构造函数参数
- 如何通过可变参数模板将多个构造函数参数转发到数组初始值设定项列表?
- 模板函数指针参数与构造函数参数
- 如何将 std::string 作为构造函数参数传递,并将其保存的 C 字符串存储在 void 指针中?
- 如何基于构造函数参数模板化类成员函数的代码
- 将派生类构造函数参数传递给受保护的成员
- 如何根据构造函数参数使用超类类型初始化成员变量?