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::apply
and 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