Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用std::forward\u作为\u元组模拟std::forward_C++_C++11_Tuples_Forwarding - Fatal编程技术网

C++ 使用std::forward\u作为\u元组模拟std::forward

C++ 使用std::forward\u作为\u元组模拟std::forward,c++,c++11,tuples,forwarding,C++,C++11,Tuples,Forwarding,假设我使用std::forward\u as\u tuple将函数调用的参数存储在一个tuple中 auto args = std::forward_as_tuple(std::forward<Args>(args)...); 这是可行的,因为std::get的右值限定版本返回std::tuple_元素&&,这是std::tuple_元素&的引用的身份转换,因为引用与&一起折叠 因此,如果std::tuple\u element\u t的计算结果为t&,则返回的类型将是t&&&,即

假设我使用
std::forward\u as\u tuple
将函数调用的参数存储在一个tuple中

auto args = std::forward_as_tuple(std::forward<Args>(args)...);
这是可行的,因为
std::get
的右值限定版本返回
std::tuple_元素&&
,这是
std::tuple_元素&
的引用的身份转换,因为引用与
&
一起折叠

因此,如果
std::tuple\u element\u t
的计算结果为
t&
,则返回的类型将是
t&&&
,即
t&
。当
std::tuple\u element\u t
返回
t&
t

我错过什么了吗?在某些情况下,这会失败吗

template <typename TupleArgs, std::size_t... Indices>
decltype(auto) forward_to_foo(TupleArgs&& args, 
                          std::index_sequence<Indices...>) {
  return foo(std::get<Indices>(std::forward<TupleArgs>(args))...);
}
我们根本不需要触摸
向前移动到\u foo
,而且我们从
参数中移动的次数不会超过一次

在您最初的实现中,对
forward\u to_foo
的任何调用都会从
TupleArgs
rvalue引用或值静默地移动,而不会在调用站点显示我们对第一个参数的破坏性

除了那个细节,是的,它模拟了转发


我自己会写一个
notstd::apply

namespace notstd {
  namespace details {
    template <class F, class TupleArgs, std::size_t... Indices>
    decltype(auto) apply(F&& f, TupleArgs&& args, 
                      std::index_sequence<Indices...>) {
      return std::forward<F>(f)(std::get<Indices>(std::forward<TupleArgs>(args))...);
    }
  }
  template <class F, class TupleArgs>
  decltype(auto) apply(F&& f, TupleArgs&& args) {
    constexpr auto count = std::tuple_size< std::decay_t<TupleArgs> >{};
    return details::apply(
      std::forward<F>(f),
      std::forward<TupleArgs>(args),
      std::make_index_sequence< count >{}
    );
  }
}
namespace notstd{
命名空间详细信息{
模板
decltype(自动)应用(F&&F、TupleArgs&&args、,
std::索引(U序列){
返回std::forward(f)(std::get(std::forward(args))…);
}
}
模板
decltype(自动)应用(F&&F、TupleArgs&&args){
constexpr auto count=std::tuple\u size{};
返回详细信息::应用(
标准:正向(f),
标准::转发(args),
std::make_index_sequence{}
);
}
}
然后我们做:

auto tuple_args = std::forward_as_tuple(std::forward<Args>(args)...);
auto call_foo = [](auto&&...args)->decltype(auto){ return foo(decltype(args)(args)...); };
return notstd::apply( call_foo, std::move(tuple_args) );
auto tuple_args=std::forward_as_tuple(std::forward(args)…);
自动调用_foo=[](自动&&…args)->decltype(自动){返回foo(decltype(args)(args);};
returnnotstd::apply(call_foo,std::move(tuple_args));

它将棘手的部分移到了
notstd::apply
,它试图匹配
std::apply
的语义,这让您可以用更标准的代码位替换它。

好吧,
TupleArgs&args
应该是
TupleArgs&args
或者
TupleArgs&args
,如果您要离开它。在调用的过程中,任何其他东西都会变得不透明,即被传递的对象发生了突变。通过值传递它只会创建底层引用的副本(我想这也很好),现在它应该是
std::forward
而不是
move
,因为
TupleArgs&&
不必是右值引用;)(如果它是一个右值引用,那么foward无论如何都会做正确的事情。其想法是将代码正确性作为一个本地属性作为一个合理的属性)@Yakk我认为
std::forward
可能不会做正确的事情,例如
std::tuple\u element\u t
是一个
t&
,而forward会导致一个左值引用,然后
std::tuple\u元素\u t&&&
将导致
t&
,这不是我想要的。但是如果传入的tuple被重用,这是正确的。只有在您还承诺不在其他上下文中重用元组本身的情况下,从元组的右值引用成员移动才有效!但是,如果元组是左值,并且一个元组元素是
T&
,不将元组转发到
get
将导致
T&
,这可能会创建一个副本,等等。或者,您的意思是,如果不首先将参数移动到函数,就应该保留该元素吗?如果元组是左值,那么这是有意义的。左值元组表示调用者以后可以重用该元组(正如您在我的call
foo
示例中看到的)。在这种情况下,在第一次调用中从参数移动是错误的。第二个调用我承诺不关心元组的状态,因此从元组中移动。只是出于好奇,为什么在新示例中为
foo()
引入lambda包装器?@quiried
foo
可能有重载。如果不选择要使用的重载,则无法将重载函数名作为对象传递。
auto tuple_args = std::forward_as_tuple(std::forward<Args>(args)...);
auto indexes = std::make_index_sequence<sizeof...(args)>{};
forward_to_foo( tuple_args, indexes );
forward_to_foo( std::move(tuple_args), indexes );
namespace notstd {
  namespace details {
    template <class F, class TupleArgs, std::size_t... Indices>
    decltype(auto) apply(F&& f, TupleArgs&& args, 
                      std::index_sequence<Indices...>) {
      return std::forward<F>(f)(std::get<Indices>(std::forward<TupleArgs>(args))...);
    }
  }
  template <class F, class TupleArgs>
  decltype(auto) apply(F&& f, TupleArgs&& args) {
    constexpr auto count = std::tuple_size< std::decay_t<TupleArgs> >{};
    return details::apply(
      std::forward<F>(f),
      std::forward<TupleArgs>(args),
      std::make_index_sequence< count >{}
    );
  }
}
auto tuple_args = std::forward_as_tuple(std::forward<Args>(args)...);
auto call_foo = [](auto&&...args)->decltype(auto){ return foo(decltype(args)(args)...); };
return notstd::apply( call_foo, std::move(tuple_args) );