Home > other >  Deduce complete type of parent from one of its template parameters
Deduce complete type of parent from one of its template parameters

Time:03-22

I want to get the typename of the parent that has a specific template parameter(key).

For example, if I have a parent MyParent<int, 1>, I want to be able to get that type(MyParent<int, 1>) from my child with just '1'. If I have MyParent<float,2> I want to be able to get that type(MyParent<float, 2>) with just '2'.

Basically, I want to get a typename (MyParent<float, 1>, MyParent<int, 2> etc.) from a "key" (1, 2, 3 etc.)

I'm using MSVC compiler, in C 20 mode.

Here's working code that does exactly that (but it has one downside):

#include <iostream>

template<std::size_t key>
class KeyClass {};

template<class Type, std::size_t key>
class parent
{
    using keyclass = KeyClass<key>;
    using self = parent<Type, key>;
public:
    template<std::same_as<keyclass> T>
    static self GetType() {}
};

class test :
    public parent<int, 1>,
    public parent<float, 2>
{
public:
    using parent<int, 1>::GetType;
    using parent<float, 2>::GetType;
};

int main()
{
    std::cout << typeid(decltype(test::GetType<KeyClass<1>>())).name() << std::endl;
    std::cout << typeid(decltype(test::GetType<KeyClass<2>>())).name() << std::endl;
}

This prints as expected: "class parent<int,1> class parent<float,2>". I can freely use those types, get their static members and do other stuff with them, and that's exactly what I want.

The downside is that I have to explicitly specify that I'm using the GetType method from every one of my parents. Which is quite lame, since I have to type everything twice (inheriting once, then specifying 'using'). Imagine having tens of keys ...

Are there any other ways to do this without repeating my code? For example, is there any way to specify 'using GetType` for all the parents in one line somehow? Or to make them automatically inherited or something, so that I don't have to specify 'using' at all?

Or maybe there's a different way to do what I want (to get a type at compile-time from some key (a template parameter), for example 1 should return Myparent<int, 1>, 2 should return MyParent<int, 2>)?

I don't want to use the preprocessor for this.

CodePudding user response:

To avoid having to write a using declaration for the members of each of the parent classes, you can write a variadic class template wrapper that exposes this member for all of the types (as in the Overloader pattern shown here)

template<typename... Ts>
struct Bases : Ts...
{
    using Ts::GetType...; 
};

And now your test class can just inherit from this wrapper as

class test : public Bases<parent<int, 1>, 
                          parent<float, 2>>
{};

Here's a demo

  • Related