See here for sample code: https://godbolt.org/z/o5osbq3bY
Hi everyone,
I'm working on some code that pulls values from a virtual machine. The interface requires both the type of the value and its index on the stack, which I've mocked into T get_one(int stack_pos).
I'm writing a wrapper that will pull N values from the stack and pushes to a C++ function.
In the sample, if you define I_LOVE_RVALUES, the code uses std::forward_as_tuple
Otherwise, it'll use std::make_tuple.
I want to forward the values from the VM to the C++ function with as little overhead as possible,
so at first I tried with the pass-by-rvalue. However, I'm getting corrupted values.
Following the advice of this thread: C++11 std::forward_as_tuple and std::forward I've thrown std::forward's everywhere, but it still doesnt work
I've switched to the pass by value version now and it works fine, but I want to understand why the Rvalue version doesn't work. My understanding is that I followed all the rules:
- Each rvalue is either used or forwarded into another Rvalue reference
- The tuple is only passed into std::applyand never used again, so its rvalues can be consumed.
My best guess is there's some interaction between the Rvalue-tuples and std::tuple_cat, but I don't really understand what's going on.
Full sample code listing:
#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;
}
If I_LOVE_RVALUES is defined, the first line is garbage. Otherwise, it should read 012
The second line should always read 012
 
    