std :: apply在很少的stackoverflow答案和n3658,n3915中提到,通常定义为:
templatedecltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence ) { return forward (f)(get(forward (t))...); } template decltype(auto) apply(F&& f, Tuple&& t) { using Indices = make_index_sequence >::value>; return apply_impl(forward (f), forward (t), Indices{}); }
但是,参考实现std :: apply函数无法在此类上下文中进行编译(使用clang 3.8和gcc 5.2进行测试):
std::apply ([] (int&) {} , std::make_tuple (42));
一种可能的解决方法是简单地从apply_impl中删除std :: forward
templatedecltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence ) { return forward (f)(get(t)...); }
这种解决方法有任何缺点吗?有更方便的解决方案吗?
更新:另一种可能的解决方法,无需更改std :: apply(受此SO答案的启发):
templateconstexpr T& make_tmp (T&& t) noexcept { return t; } ... std::apply ([] (int& i) {} , make_tmp (std::make_tuple (42)));
它是否正确并且结果定义明确?
如果您有一个包含临时对象的临时元组(或对临时对象的引用),则需要可写引用的函数拒绝该应用程序是正确的.该函数希望调用者注意它所写的内容,并确定丢弃它.
这是编译的代码:
int main() { int i = 42; std::apply ([] (int&) {} , std::tie(i) ); }
make_tuple
创建一个副本元组. apply
然后f
在即将被丢弃的副本上调用传入:这些被正确地视为rvalues.
如果你有一个想要通过引用传递的对象,请std::apply
在元组中引用它,而不是它的副本.然后,元组的右值岬内apply
并不能适用于引用内容.
对于std::get
返回一个右值,则:
(A)第n个元素必须是副本,元组必须是rvalue
(B)第n个元素必须是右值引用,元组必须是右值引用
通过存储左值引用,std::get
永远不会返回右值引用.
您可能想要打电话std::tie
或std::forward_as_tuple
视情况而定. std::make_tuple
当您想要在元组中创建副本时,而不是在存储对其他对象的引用时.
有一些方法可以让你通过右值作为左值,当你不希望放弃任何修改,但这些通常是不好的想法,他们应该与大警告标签客户端代码库来完成所有的地方,不含蓄.
templateT& as_lvalue( T&& t ) { return t; }
很简单.