【发布时间】:2017-08-31 20:22:50
【问题描述】:
我最近一直在研究 C++ 中的转发引用,下面是我目前对该概念的理解的快速总结。
假设我有一个模板函数foo对T 类型的单个参数进行转发引用。
template<typename T>
void foo(T&& arg);
如果我使用左值调用此函数,则 T 将被推断为 T&,由于引用折叠规则 T& && -> T&,arg 参数的类型为 T&。
如果使用未命名的临时函数调用此函数,例如函数调用的结果,则 T 将被推断为 T,从而使 arg 参数的类型为 T&&。
然而,在 foo 内部,arg 是一个命名参数,因此如果我想将参数传递给其他函数并仍保持其值类别,则需要使用 std::forward。
template<typename T>
void foo(T&& arg)
{
bar(std::forward<T>(arg));
}
据我了解,cv 限定符不受此转发的影响。这意味着,如果我使用命名的 const 变量调用 foo,那么 T 将被推断为 const T&,因此由于引用折叠规则,arg 的类型也将是 const T&。对于 const 右值,T 将被推导出为 const T,因此 arg 将是 const T&& 类型。
这也意味着,如果我在 foo 中修改 arg 的值,如果我确实将一个 const 变量传递给它,我将得到一个编译时错误。
现在谈谈我的问题。 假设我正在编写一个容器类,并希望提供一种将对象插入容器的方法。
template<typename T>
class Container
{
public:
void insert(T&& obj) { storage[size++] = std::forward<T>(obj); }
private:
T *storage;
std::size_t size;
/* ... */
};
通过使insert 成员函数对obj 进行转发引用,如果insert 实际上传递了一个临时对象,我可以使用std::forward 来利用存储类型T 的移动赋值运算符.
以前,当我对转发引用一无所知时,我会编写此成员函数并采用 const 左值引用:
void insert(const T& obj).
这样做的缺点是,如果 insert 被传递了一个临时对象,则此代码不会利用(可能更有效的)移动赋值运算符。
假设我没有错过任何东西。
是否有任何理由为插入函数提供两个重载?一个采用 const 左值引用,一个采用转发引用。
void insert(const T& obj);
void insert(T&& obj);
我问的原因是 the reference documentation for std::vectorstates push_back 方法有两个重载。
void push_back (const value_type& val);
void push_back (value_type&& val);
为什么需要第一个版本(采用const value_type&)?
【问题讨论】:
-
您的
insert(T&& obj)不是转发参考。它是由班级修复的。