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

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

请参阅此处获取示例代码: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

vzgqcmou

vzgqcmou1#

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

相关问题