请参阅此处获取示例代码: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
之间有一些交互,但我真的不明白发生了什么。
完整示例代码列表:
#include <iostream>
#include <string>
#include <vector>
#include <tuple>
#include <cxxabi.h>
#define I_LOVE_RVALUES
#ifdef I_LOVE_RVALUES
#define tuple_creator std::forward_as_tuple
#else
#define tuple_creator std::make_tuple
#endif
template<typename T>
T get_one(int stack_pos)
{
// std::cout << typeid(T).name() + std::to_string(i) << std::endl;
return static_cast<T>(stack_pos);
}
template<typename T>
inline auto get_all(int i)
{
return tuple_creator(std::forward<T>(get_one<T>(i)));
}
// recursive case
template<typename T0, typename T1, typename ...T>
inline auto get_all(int i)
{
return std::tuple_cat(
tuple_creator(std::forward<T0>(get_one<T0>(i))),
get_all<T1, T...>(i+1)
);
}
void print_all(int i, float f1, float f2)
{
std::cout << i << f1 << f2 << std::endl;
}
int main()
{
auto&& tup = get_all<int, float, float>(0);
std::string tup_typeid_name = typeid(decltype(tup)).name();
std::apply(print_all, tup);
// here i'll make my forward_as_tuple directly
std::apply(print_all, std::forward_as_tuple(std::move(0), std::move(1), std::move(2)));
std::cout << tup_typeid_name << std::endl;
}
如果定义了I_LOVE_RVALUES
,则第一行是垃圾。否则,它应读取012
第二行应始终为012
1条答案
按热度按时间vzgqcmou1#
get_one
返回一个prvalue。为了将其传递给forward_as_tuple
,创建了一个临时对象,然后得到的元组引用该临时对象。但是这个临时函数将在包含调用的完整表达式的末尾被销毁--在您的例子中,get_all
一返回就被销毁。最后,
forward_as_tuple
生成一个引用元组,但是引用的东西仍然必须存储在 * 某个地方 *。