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

时间:2016-01-08 02:51:18

标签: c++ c++11 c++14 c++17

少数stackoverflow答案和n3658n3915中提到了

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}}

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

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::tiestd::forward_as_tuplestd::make_tuple用于在元组中创建副本,而不是在存储对其他对象的引用时。

当你希望放弃任何修改时,有很多方法可以让rvalues作为左值传递,但这些通常是糟糕的想法,它们应该在带有大警告贴纸的客户端代码中完成在这个地方,而不是隐含在图书馆里。

template<class T>
T& as_lvalue( T&& t ) { return t; }

很简单。