通用引用参数使用了两次
Universal reference argument used twice
我希望围绕std::make_pair创建一个包装器,该包装器接受一个参数,并使用该参数生成对的第一个和第二个成员。此外,我希望利用移动语义。
天真地,我们可能会写(为了清楚起见,忽略返回类型(,
template <typename T>
void foo(T&& t)
{
std::make_pair(std::forward<T>(t),
std::forward<T>(t));
}
但这不太可能达到我们想要的效果。
我们想要的是:
- 在使用(const(lvalue引用参数调用foo的情况下,我们应该将该(const的(引用传递给std::make_pair,而不修改这两个参数
- 在使用右值引用参数调用foo的情况下,我们应该复制被引用的对象,然后使用原始右值引用以及对新创建的对象的右值引用来调用std::make_pair
到目前为止,我想到的是:
template <typename T>
T forward_or_duplicate(T t)
{
return t;
}
template <typename T>
void foo(T&& t)
{
std::make_pair(std::forward<T>(t),
forward_or_duplicate<T>(t));
}
但我有理由相信这是错误的。
所以,问题:
这行得通吗?我怀疑不是因为,如果用右值引用调用foo((,那么在构造通过值传递给forward_or_duplicate((的T时,将调用T的move构造函数(如果存在(,从而破坏T。
即使它确实有效,它是最优的吗?同样,我怀疑当从forward_or_duplicate((返回T时,不会调用T的复制构造函数。
这似乎是一个常见的问题。有惯用的解决方案吗?
所以,问题:
- 这行得通吗?我怀疑不是因为如果用右值引用调用foo((,那么T的move构造函数(如果存在的话(将是在构造通过值传递给的T时调用forward_or_duplicate((,从而销毁t
否,foo
中的t
是一个左值,因此构造由值传递给的T
来自t
的forward_or_duplicate()
调用复制构造函数。
- 即使它确实有效,它是最优的吗?同样,我怀疑在从forward_or_duplicate((
不,t
是一个函数参数,所以返回隐含地移动,而不是复制。
也就是说,这个版本将更加高效和安全:
template <typename T>
T forward_or_duplicate(std::remove_reference_t<T>& t)
{
return t;
}
如果T
是左值引用,则会产生与以前相同的签名。如果T
不是参考,这将为您节省一次移动。此外,它将T
放入一个非推导上下文中,这样您就不会忘记指定它
您的确切代码是有效的。它的微小变化(即不调用make_pair
,而是调用其他一些函数(会导致未指定的结果。即使它看起来有效,远离这行代码的细微变化(本地正确的(也会破坏它
您的解决方案不是最优的,因为它可以复制T
两次,即使它工作,也只需要复制一次。
这是迄今为止最简单的解决方案。它不能修复其他地方的代码更改引起的细微中断,但如果您真的在调用make_pair
,那就不成问题了:
template <typename T>
void foo(T&& t) {
std::make_pair(std::forward<T>(t),
static_cast<T>(t));
}
对于推导类型T&&
,如果T&&
是左值,则static_cast<T>(t)
是noop;如果T&&
是右值,则为copy。
当然,static_cast<T&&>(t)
也可以代替std::forward<T>(t)
,但人们也不这么做。
我经常这样做:
template <typename T>
void foo(T&& t) {
T t2 = t;
std::make_pair(std::forward<T>(t),
std::forward<T>(t2));
}
但这阻碍了一个理论省略的机会(这里没有发生(。
通常,在与static_cast<T>(t)
相同的函数调用上调用std::forward<T>(t)
或任何等效的复制或转发函数是个坏主意。未指定参数的求值顺序,因此,如果使用std::forward<T>(t)
的参数不是T&&
类型,并且其构造函数看到右值T
并从中移出状态,则static_cast<T>(t)
可以在t
的状态被剥离后求值。
这里不会发生这种情况:
template <typename T>
void foo(T&& t) {
T t2 = t;
std::make_pair(std::forward<T>(t),
std::forward<T>(t2));
}
因为我们将副本移到另一行,在那里初始化t2
。
虽然T t2=t;
看起来总是复制,但如果T&&
是左值引用,则T
也是左值引用而int& t2 = t;
不复制。
- g++的分段错误(在NaN上使用to_string两次时)
- 蛇在C++不会连续转两次
- 检查一个数组是否包含在另一个数组中,以相反的顺序,至少两次
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 我应该如何去缓解两次出现的cin?
- Realloc 两次无法在 Visual Studio 上运行
- 使用 getline(cin, var) 两次在进行字符串比较时会产生错误 (==)
- 为什么映射插入和 map.find() 的单次迭代比插入和 map.find() 的两次单独迭代慢得多
- C++析构函数调用两次,堆栈分配的复合对象
- 为什么参数在构造 std::thread 时移动两次
- Qt插槽调用了两次
- 做 std::用相同的unique_ptr移动两次
- 从工厂方法返回的ComPtr的引用计数增加两次
- 如果参数传递两次,会发生什么情况?一次按值,一次按引用?是否会修改
- C++重载运算符两次,一个返回非常量引用,另一个返回常量引用,首选项是什么
- 给定以下代码(在GCC 4.3中),为什么两次转换为引用
- 调用对数组引用两次的函数
- C++重载getter两次,一次返回指针,另一次返回常量引用,都失败了
- Java用JNI调用C++:为什么JNIEnv指针被取消引用两次
- 通用引用参数使用了两次