gpt4 book ai didi

c++ - 模板代码中的转发引用与 const 左值引用

转载 作者:可可西里 更新时间:2023-11-01 17:56:35 24 4
gpt4 key购买 nike

我最近一直在研究 C++ 中的转发引用,下面是我目前对该概念的理解的快速总结。

假设我有一个模板函数 fooT 类型的单个参数进行转发引用.

template<typename T>
void foo(T&& arg);

如果我用左值调用这个函数,那么 T将被推断为 T&制作arg参数类型为 T&由于引用折叠规则 T& && -> 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&& 类型.

这也意味着如果我修改arg的值里面foo如果我确实向它传递了一个 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我可以使用 std::forward利用存储类型的移动赋值运算符 T如果insert实际上传递了一个临时对象。

以前,当我对转发引用一无所知时,我会编写这个采用 const 左值引用的成员函数: void insert(const T& obj) .

这样做的缺点是这段代码没有利用(可能更有效)移动赋值运算符 if insert传递了一个临时对象。

假设我没有遗漏任何东西。

是否有任何理由为插入函数提供两个重载?一种采用 const 左值引用,另一种采用转发引用。

void insert(const T& obj);
void insert(T&& obj);

我问的原因是 the reference documentation for std::vector 表示 push_back方法有两个重载。

void push_back (const value_type& val);
void push_back (value_type&& val);

为什么需要第一个版本(取 const value_type&)?

最佳答案

你必须小心函数模板,而不是类模板的非模板方法。您的成员 insert 本身不是模板。这是一个模板类的方法。

Container<int> c;
c.insert(...);

我们可以很容易地看到 T 没有在第二行推导出来,因为它已经在第一行固定为 int,因为 T 是类的模板参数,而不是方法。

类模板的非模板方法,仅在一个方面与常规方法不同,一旦类被实例化:它们不会被实例化,除非它们被实际调用。这很有用,因为它允许模板类与类型一起工作,对于这些类型,只有一些方法有意义(STL 容器充满了这样的例子)。

最重要的是,在我上面的示例中,由于 T 固定为 int,因此您的方法变为:

void insert(int&& obj) { storage[size++] = std::forward<int>(obj); }

这根本不是一个转发引用,而只是通过右值引用获取,即它只绑定(bind)到右值。这就是为什么您通常会看到像 push_back 这样的东西有两个重载,一个用于左值,一个用于右值。

关于c++ - 模板代码中的转发引用与 const 左值引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45989511/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com