Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get base classes as tuple

This is follow-up to Wrap each base class in a template class .

Playing around, I figured out a way to convert a tuple of distinct types to a struct inheriting from each of them:

#include <cstdio>
#include <tuple>
#include <type_traits>

namespace detail {

template <typename... Ts>
struct tuple_to_struct_impl : Ts... {};

}

template <typename>
struct tuple_to_struct;

template <typename... Ts>
struct tuple_to_struct<std::tuple<Ts...>> :
    detail::tuple_to_struct_impl<Ts...> {};

struct x { int i; };
struct y { int j; };
struct z { int k; };

using t = std::tuple<x, y, z>;
using xyz = tuple_to_struct<t>;

int main() {
    xyz s{ 1, 2, 3 };
    std::printf("%d, %d, %d", s.i, s.j, s.k);
}

Run it on GodBolt

Is there a way to reverse this, i.e. implement struct_to_tuple? std::is_base_of requires to know both types up front, so I would have to run it with a list of all possible candidates, e.g. struct_to_tuple<xyz, x, y, z, std::string...>.

Get base class for a type in class hierarchy touches on the topic, but looks out of date with some speculation on C++14. It also lists multiple inheritance as a problem, while it is exactly what I want.

like image 381
Dominik Kaszewski Avatar asked Nov 18 '25 07:11

Dominik Kaszewski


1 Answers

The answer you link is still correct. There are more related questions that suggest std::bases type trait was proposed but rejected (see eg Status of std::bases and std::direct_bases). However, gcc supports it as tr2:

A rather simplistic demo:

#include <tr2/type_traits>
#include <type_traits>

struct foo {};
struct bar {};
struct derived : foo,bar {};
struct derived2 : foo,bar {};
int main() {
    using x = std::tr2::direct_bases<derived>::type;
    using y = std::tr2::direct_bases<derived2>::type;
    static_assert(std::is_same<x,y>::value);
    static_assert(std::is_same<x,std::tr2::__reflection_typelist<foo,bar>>::value);
}

Live Demo

For a portable way you will have to wait until proper reflection is in.

Combining Jarod42's version from a comment with your trait, we can see that it actually works, by constructing xyz from the tuple, get its bases, put them in a tuple, turn that tuple again to a struct with base classes and see that it is the same type as the original xyz:

#include <tr2/type_traits>
#include <type_traits>
#include <cstdio>
#include <tuple>
#include <type_traits>

template <typename> struct tuple_to_struct;
template <typename... Ts> struct tuple_to_struct<std::tuple<Ts...>> : Ts... {};

template <typename> struct typelist_to_tuple;
template <typename... Ts> struct typelist_to_tuple<std::tr2::__reflection_typelist<Ts...>> {
    using type = std::tuple<Ts...>;
};
template <typename T> using typelist_to_tuple_t = typename typelist_to_tuple<T>::type;

struct x { int i; };
struct y { int j; };
struct z { int k; };

using t = std::tuple<x, y, z>;
using xyz = tuple_to_struct<t>;
 
int main() {
    xyz s{ 1, 2, 3 };
    std::printf("%d, %d, %d", s.i, s.j, s.k);

    using bases = std::tr2::direct_bases<xyz>::type;
    using base_tuple = typelist_to_tuple_t<bases>;
    using abc = tuple_to_struct<base_tuple>;
    static_assert(std::is_same_v<abc,xyz>);
}

Live Demo

like image 104
463035818_is_not_a_number Avatar answered Nov 19 '25 23:11

463035818_is_not_a_number



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!