I want to store multiple non-movable types in a single variable.
At the very first, I have tried std::tuple at the very first, but it fails.
#include <tuple>
template<typename T>
struct No {
No(T){}
No(const No &) = delete;
No(No &&) = delete;
};
struct Handmade {
No<int> a;
No<double> b;
No<char> c;
};
template<typename T>
auto no() -> No<T> { return No<T>(T()); }
auto main() -> int
{
Handmade h = {no<int>(), no<double>(), no<char>()}; // good
auto tuple = std::make_tuple(no<int>(), no<double>(), no<char>()); // fails
return 0;
}
Here, Handmade
type can be initialized through aggregate initialization.
However, std::tuple
is not aggregate-initialzable, it doesn't work.
Since it should be variadic, I cannot write such type Handmade
for my purpose.
Is it possible to implement such variadic tepmlate data structure in current C standard or is there any workaround?
CodePudding user response:
Yes, you can write your own aggregate tuple like this:
template <int I, typename T>
struct MyTupleElem
{
T value{};
template <int J> requires(I == J) T &get() {return value;}
template <int J> requires(I == J) const T &get() const {return value;}
};
template <typename T, typename ...P>
struct MyTupleHelper;
template <int ...I, typename ...P>
struct MyTupleHelper<std::integer_sequence<int, I...>, P...>
: MyTupleElem<I, P>...
{
using MyTupleElem<I, P>::get...;
};
template <typename ...P>
struct MyTuple : MyTupleHelper<std::make_integer_sequence<int, sizeof...(P)>, P...> {};
template <typename ...P>
MyTuple(P &&...) -> MyTuple<std::decay_t<P>...>;
template <typename T>
struct No
{
T value;
No(T value) : value(value) {}
No(const No &) = delete;
No(No &&) = delete;
};
template <typename T>
No<T> no(T t) {return No<T>(t);}
int main()
{
MyTuple h = {no<int>(1), no<double>(2.3), no<char>('4')};
std::cout << h.get<0>().value << '\n';
std::cout << h.get<1>().value << '\n';
std::cout << h.get<2>().value << '\n';
}
And I think it's a good way to make tuples in general, even if you don't want aggregate-ness. Last time I tested, such tuples could tolerate more elements than the classic ones with the bases chained on top of each other.