当前位置:  开发笔记 > 编程语言 > 正文

std :: apply可能无法正确实施

如何解决《std::apply可能无法正确实施》经验,为你挑选了1个好方法。

std :: apply在很少的stackoverflow答案和n3658,n3915中提到,通常定义为:

template 
decltype(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 ,但保持通用引用不变:

template 
decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence) {
  return forward(f)(get(t)...);
}

这种解决方法有任何缺点吗?有更方便的解决方案吗?

更新:另一种可能的解决方法,无需更改std :: apply(受此SO答案的启发):

template  constexpr T& make_tmp (T&& t) noexcept { return t; }
...
std::apply ([] (int& i) {} , make_tmp (std::make_tuple (42)));

它是否正确并且结果定义明确?



1> Yakk - Adam ..:

如果您有一个包含临时对象的临时元组(或对临时对象的引用),则需要可写引用的函数拒绝该应用程序是正确的.该函数希望调用者注意它所写的内容,并确定丢弃它.

这是编译的代码:

int main() {
  int i = 42;
  std::apply ([] (int&) {} , std::tie(i) );
}

make_tuple创建一个副本元组. apply然后f在即将被丢弃的副本上调用传入:这些被正确地视为rvalues.

如果你有一个想要通过引用传递的对象,请std::apply在元组中引用它,而不是它的副本.然后,元组的右值岬内apply不能适用于引用内容.

对于std::get(some_tuple)返回一个右值,则:

(A)第n个元素必须是副本,元组必须是rvalue

(B)第n个元素必须是右值引用,元组必须是右值引用

通过存储左值引用,std::get永远不会返回右值引用.

您可能想要打电话std::tiestd::forward_as_tuple视情况而定. std::make_tuple当您想要在元组中创建副本时,而不是在存储对其他对象的引用时.

有一些方法可以让你通过右值作为左值,当你希望放弃任何修改,但这些通常是不好的想法,他们应该与大警告标签客户端代码库来完成所有的地方,不含蓄.

template
T& as_lvalue( T&& t ) { return t; }

很简单.

推荐阅读
地之南_816
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有