Search code examples
c++templatestuples

How can I have each `using` of a base struct be a different type?


I have a tuple of elements that I want to access using std::get with the type name:

template<typename... Params>
struct SomeType
{
    std::tuple<Params...> params;
};

using TypeOne = SomeType<std::string, int, double>;
using TypeTwo = SomeType<std::string, std::string, int>;
using TypeThree = SomeType<std::string, int, double>;

...

std::tuple<TypeOne, TypeTwo, TypeThree> tuple;

//Works via index, but I want to use the type
auto first = std::get<0>(tuple);
auto second = std::get<1>(tuple);
auto third = std::get<2>(tuple);

//Doesn't work here since TypeOne and TypeThree are the same
auto onth = std::get<TypeOne>(tuple);
auto twoth = std::get<TypeTwo>(tuple);
auto threeth = std::get<TypeThree>(tuple);

My current resolution is to have the first parameter be a lambda type:

template<typename ID, typename... Params>
struct SomeTypeWithId
{
    SomeTypeWithId(Params... _params)
        : params(std::make_tuple(_params...))
    {}

    std::tuple<Params...> params;
};

using TypeOneWithID = SomeTypeWithId<decltype([](){}), std::string, int, double>;
using TypeTwoWithID = SomeTypeWithId<decltype([](){}), std::string, std::string, int>;
using TypeThreeWithID = SomeTypeWithId<decltype([](){}), std::string, int, double>;

std::tuple<TypeOneWithID, TypeTwoWithID, TypeThreeWithID> tuple;

//Works since they're all different types now
auto onth = std::get<TypeOneWithID>(tuple);
auto twoth = std::get<TypeTwoWithID>(tuple);
auto threeth = std::get<TypeThreeWithID>(tuple);

But the syntax here is annoying as I do not want to have to always have to put decltype([](){}) in all my using declaratives. I thought I could get away with something like this:

template<typename ID, typename... Params>
struct SomeTypeWithId;

template<typename... Params>
struct SomeTypeWithId<decltype([](){}), Params...>
{
    SomeTypeWithId(Params... _params)
        : params(std::make_tuple(_params...))
    {}

    std::tuple<Params...> params;
};

But it doesn't work. How can I achieve this? My issue is that the index of the elements will likely change (across various tuples), but their names will not.

Compile Explorer Playground


Solution

  • You could just define types instead of making typedefs:

    template <class... Params>
    struct SomeType {
        std::tuple<Params...> params;
    };
    
    struct TypeOneWithID : SomeType<std::string, int, double> {};
    struct TypeTwoWithID : SomeType<std::string, std::string, int> {};
    struct TypeThreeWithID : SomeType<std::string, int, double> {};