Does the stdlib provide a type list?
Asked Answered
G

3

6

In modern C++, does the standard library provide a type list template?

int main() {
    using int_types = type_list<int,long,short,char>;
    std::cout << length<int_types>::value << ' '
              << typeid(element<2,int_types>::type).name();
}

Note that int_types does not store any values (as std::tuple does). It's merely a list of types.

Guitar answered 16/6, 2019 at 11:17 Comment(4)
Presumably std::tuple won't do because int_types objects are created at some point? It's implied by your remark, just want to clarify that point.Hypoglossal
Short answer: no, long answer: nyet :-) Perhaps if you indicated what you wanted to do (rather than how), we could assist more. In other words, what are you actually trying to achieve?Fredkin
Why not use an std::tuple which you never need to instantiate? tuple_size and tuple_element let you query the type list at compile time.Ninfaningal
@interjay: Because sometimes (for example, when picking overloaded functions) I might have to instantiate it.Guitar
G
0

In the end, I did something like this:

template<typename ...T> struct type_list {};

template<typename    L> struct length;
template<typename ...T> struct length<type_list<T...>> {static const std::size_t value=sizeof...(T);};

template<std::size_t I, typename L>
struct element;
template<typename F, typename ...T> 
struct element<0, type_list<F, T...>> {using type=F;};
template<std::size_t I> 
struct element<I, type_list<>>        {using type=void;};
template<std::size_t I, typename F, typename ...T> 
struct element<I, type_list<F, T...>> {using type=typename element<I-1,type_list<T...>>::type;};

int main() {
    using int_types = type_list<int,long,short,char>;
    std::cout << length<int_types>::value << '\n'
              << typeid(element<2,int_types>::type).name() << '\n';
    return 0;
}
Guitar answered 12/9, 2019 at 14:3 Comment(0)
T
3

It seems to me that, in modern C++ standard library, nearest what you want is std::tuple.

If the problem is that std::tuple store values of the listed types (so, I suppose, can be a problem instantiate an object of that type) it's easy write a instantiable object that wraps a std::tuple using without instantiate the std::tuple itself.

I mean... given a wrapper like this

template <typename ... Ts>
struct wrapTuple
 {
   using type = std::tuple<Ts...>;

   template <std::size_t N>
   using element = std::tuple_element_t<N, type>;

   static constexpr auto length { std::tuple_size_v<type> };
 };

you can write the following lines without instantiate the wrapper

   using int_types = wrapTuple<int, long, short, char>;

   std::cout << int_types::length << ' '
      << typeid(int_types::element<2u>).name() << std::endl;

but you can also instantiate it without instantiate the std::tuple

   int_types it;

   std::cout << it.length << ' '
      << typeid(decltype(it)::element<2u>).name() << std::endl;
Tuesday answered 16/6, 2019 at 11:53 Comment(1)
While this works (+1), it is an ugly workaround that requires documentation in order for others to understand it. I might just use my own type list template then. Those are easy to understand and good naming gets the purpose across without need for extensive documentation for the intent.Guitar
P
2

Use std::tuple type but don't instantiate it:

#include <iostream>
#include <tuple>

int main()
{
    using int_types = std::tuple<int, long, short, char>;
    std::cout << std::tuple_size_v<int_types> << ' '
        << typeid(std::tuple_element_t<2, int_types>).name();
}

MSVC output:

4 short

GCC output:

4 s

Clang output:

4 s
Padding answered 16/6, 2019 at 11:31 Comment(3)
Not sure but I suspect that the OP prefer std::tuple_element_t instead of std::tuple_element.Tuesday
@Tuesday yes, I think so. Thanks for pointing out, it makes more sense nowPadding
I could use tuple (+1), but I'd need to wrap it like max66 showed in his answer, because sometimes (see here I might have to instantiate it.Guitar
G
0

In the end, I did something like this:

template<typename ...T> struct type_list {};

template<typename    L> struct length;
template<typename ...T> struct length<type_list<T...>> {static const std::size_t value=sizeof...(T);};

template<std::size_t I, typename L>
struct element;
template<typename F, typename ...T> 
struct element<0, type_list<F, T...>> {using type=F;};
template<std::size_t I> 
struct element<I, type_list<>>        {using type=void;};
template<std::size_t I, typename F, typename ...T> 
struct element<I, type_list<F, T...>> {using type=typename element<I-1,type_list<T...>>::type;};

int main() {
    using int_types = type_list<int,long,short,char>;
    std::cout << length<int_types>::value << '\n'
              << typeid(element<2,int_types>::type).name() << '\n';
    return 0;
}
Guitar answered 12/9, 2019 at 14:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.