gcc 使用std::forward_as_tuple和std::tuple_cat转发参数

iswrvxsc  于 2023-04-30  发布在  其他
关注(0)|答案(1)|浏览(215)

请参阅此处获取示例代码:https://godbolt.org/z/o5osbq3bY
大家好
我正在编写一些从虚拟机中提取值的代码。该接口需要值的类型及其在堆栈上的索引,我将其模拟为T get_one(int stack_pos)。我正在编写一个 Package 器,它将从堆栈中提取N值,并将其推送到C函数中。
在示例中,如果定义了I_LOVE_RVALUES,则代码使用std::forward_as_tuple,否则将使用std::make_tuple。我想用尽可能少的开销将值从VM转发到C
函数,所以一开始我尝试使用pass-by-rvalue。但是,我得到了损坏的值。
遵循这个线程的建议:C++11 std::forward_as_tuple and std::forward我把std::forward扔得到处都是,但它仍然不起作用
我现在已经切换到了通过值传递的版本,它工作得很好,但我想知道为什么Rvalue版本不工作。我的理解是,我遵守了所有的规则:
1.每个右值要么被使用,要么被转发到另一个右值引用
1.元组只传递到std::apply中,不再使用,所以它的右值可以被消耗。
我最好的猜测是Rvalue-tuples和std::tuple_cat之间有一些交互,但我真的不明白发生了什么。

完整示例代码列表:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <tuple>
  5. #include <cxxabi.h>
  6. #define I_LOVE_RVALUES
  7. #ifdef I_LOVE_RVALUES
  8. #define tuple_creator std::forward_as_tuple
  9. #else
  10. #define tuple_creator std::make_tuple
  11. #endif
  12. template<typename T>
  13. T get_one(int stack_pos)
  14. {
  15. // std::cout << typeid(T).name() + std::to_string(i) << std::endl;
  16. return static_cast<T>(stack_pos);
  17. }
  18. template<typename T>
  19. inline auto get_all(int i)
  20. {
  21. return tuple_creator(std::forward<T>(get_one<T>(i)));
  22. }
  23. // recursive case
  24. template<typename T0, typename T1, typename ...T>
  25. inline auto get_all(int i)
  26. {
  27. return std::tuple_cat(
  28. tuple_creator(std::forward<T0>(get_one<T0>(i))),
  29. get_all<T1, T...>(i+1)
  30. );
  31. }
  32. void print_all(int i, float f1, float f2)
  33. {
  34. std::cout << i << f1 << f2 << std::endl;
  35. }
  36. int main()
  37. {
  38. auto&& tup = get_all<int, float, float>(0);
  39. std::string tup_typeid_name = typeid(decltype(tup)).name();
  40. std::apply(print_all, tup);
  41. // here i'll make my forward_as_tuple directly
  42. std::apply(print_all, std::forward_as_tuple(std::move(0), std::move(1), std::move(2)));
  43. std::cout << tup_typeid_name << std::endl;
  44. }

如果定义了I_LOVE_RVALUES,则第一行是垃圾。否则,它应读取012
第二行应始终为012

vzgqcmou

vzgqcmou1#

get_one返回一个prvalue。为了将其传递给forward_as_tuple,创建了一个临时对象,然后得到的元组引用该临时对象。但是这个临时函数将在包含调用的完整表达式的末尾被销毁--在您的例子中,get_all一返回就被销毁。
最后,forward_as_tuple生成一个引用元组,但是引用的东西仍然必须存储在 * 某个地方 *。

相关问题