std :: apply,通常定义为:
std::apply ([] (int&) {} , std::make_tuple (42));
但是参考实现std :: apply函数无法在这样的上下文中编译(使用clang 3.8和gcc 5.2进行测试):
template <typename F, typename Tuple, size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence<I...>) {
return forward<F>(f)(get<I>(t)...);
}
一种可能的解决方法是简单地删除std :: forward&lt; Tuple&gt;来自 apply_impl ,但保留通用引用:
template <typename T> constexpr T& make_tmp (T&& t) noexcept { return t; }
...
std::apply ([] (int& i) {} , make_tmp (std::make_tuple (42)));
这种解决方法有什么缺点吗?是否有更方便的解决方案?
更新:另一种可能的解决方法,无需更改 std :: apply (受此SO answer启发):
{{1}}
它是否正确且结果定义明确?
答案 0 :(得分:5)
如果您有一个包含临时对象的临时元组(或对临时对象的引用),则需要可写引用的函数才能拒绝该应用程序。该函数希望调用者注意它所写的内容,并确定丢弃它。
以下是编译的代码:
int main() {
int i = 42;
std::apply ([] (int&) {} , std::tie(i) );
}
make_tuple
创建副本元组。 apply
然后在即将被丢弃的副本上调用传入的f
:这些被正确地视为rvalues。
如果你想通过std::apply
通过引用传递一个对象,请在元组中引用它,而不是它的副本。然后apply
内元组的右值确实不适用于参考内容。
要让std::get<N>(some_tuple)
返回右值,请执行以下操作:
(A)第n个元素必须是副本,元组必须是右值
(B)第n个元素必须是右值引用,元组必须是右值引用
通过存储左值引用,std::get
将永远不会返回右值引用。
您可能希望根据具体情况致电std::tie
或std::forward_as_tuple
。 std::make_tuple
用于在元组中创建副本,而不是在存储对其他对象的引用时。
当你做希望放弃任何修改时,有很多方法可以让rvalues作为左值传递,但这些通常是糟糕的想法,它们应该在带有大警告贴纸的客户端代码中完成在这个地方,而不是隐含在图书馆里。
template<class T>
T& as_lvalue( T&& t ) { return t; }
很简单。