If all of the members of std::tuple
are of standard layout types, is that std::tuple
itself standard layout? The presence of a user-defined copy-constr
Inspired by PotatoSwatter's answer, I've dedicated my day to creating a standard layout tuple for C++14.
The code actually works, but is not currently suited for use as it involves undefined behaviour. Treat it as a proof-of-concept. Here's the code I ended up with:
#include
#include
#include
#include
#include
//get_size
template
constexpr size_t get_size()
{
return sizeof(T_head);
}
template
constexpr size_t get_size()
{
return get_size() + get_size();
}
//concat
template
constexpr std::array concat(const std::array& a1, const std::array& a2, std::index_sequence, std::index_sequence)
{
return { a1[I1]..., a2[I2]... };
}
template
constexpr std::array concat(const std::array& a1, const std::array& a2)
{
return concat(a1, a2, std::make_index_sequence{}, std::make_index_sequence{});
}
//make_index_array
template
constexpr std::array make_index_array()
{
return {T_offset};
}
template
constexpr std::array make_index_array()
{
return concat(
make_index_array(),
make_index_array()
);
}
template
constexpr std::array make_index_array()
{
return make_index_array<0, T_args...>();
}
template
using T_param = typename std::tuple_element>::type;
template
struct standard_layout_tuple
{
static constexpr std::array index_array = make_index_array();
char storage[get_size()];
//Initialization
template
void initialize(T_val&& val)
{
void* place = &this->storage[index_array[T_index]];
new(place) T_val(std::forward(val));
}
template
void initialize(T_val&& val, T_val2&& val2, T_vals_rest&&... vals_rest)
{
initialize(std::forward(val));
initialize(std::forward(val2), std::forward(vals_rest)...);
}
void initialize(T_args&&... args)
{
initialize<0, T_args...>(std::forward(args)...);
}
standard_layout_tuple(T_args&&... args)
{
initialize(std::forward(args)...);
}
//Destruction
template
void destroy()
{
T_val* place = reinterpret_cast(&this->storage[index_array[T_index]]);
place->~T_val();
}
template
void destroy()
{
destroy();
destroy();
}
void destroy()
{
destroy<0, T_args...>();
}
~standard_layout_tuple()
{
destroy();
}
template
void set(T_param&& data)
{
T_param* ptr = reinterpret_cast*>(&this->storage[index_array[T_index]]);
*ptr = std::forward>(data);
}
template
T_param& get()
{
return *reinterpret_cast*>(&this->storage[index_array[T_index]]);
}
};
int main() {
standard_layout_tuple sltuple{5.5f, 3.4, 7, 1.22};
sltuple.set<2>(47);
std::cout << sltuple.get<0>() << std::endl;
std::cout << sltuple.get<1>() << std::endl;
std::cout << sltuple.get<2>() << std::endl;
std::cout << sltuple.get<3>() << std::endl;
std::cout << "is standard layout:" << std::endl;
std::cout << std::boolalpha << std::is_standard_layout>::value << std::endl;
return 0;
}
Live example: https://ideone.com/4LEnSS
There's a few things I'm not happy with:
This is not yet suitable for use as-is, really only treat it as a proof-of-concept in this state. I will probably come back to improve on some of these issues. Or, if anyone else can improve it, feel free to edit.