C++ - Deducing type from inherited constructor's arguments for class template
Asked Answered
A

2

5

I have a class template that inherits the constructors of the base class template. (As for c++20) Is there a way to deduce the template arguments of the derived class from the constructor arguments of base?

If I specify the type explicitly, that works. Or if I reimplement the constructor and call the constructor of base, that also would work but is there a way to do without that?

template<typename T>
struct CTestBase
{
    using Type = T;

    CTestBase() = default;
    CTestBase(T t){}
};

template<typename T>
struct CTestDer : public CTestBase<T>
{
    using CTestBase<T>::CTestBase;
};

void test()
{
    //CTestDer der(int{}); //ERROR
    CTestDer<int> der(int{}); //OK
}
Afb answered 30/1, 2022 at 14:46 Comment(0)
L
8

You can add a user-defined deduction guide:

#include <utility>

template<typename T>
struct CTestBase
{
    using Type = T;

    CTestBase() = default;
    CTestBase(T t){}
};

template<typename T>
struct CTestDer : public CTestBase<T>
{
    using CTestBase<T>::CTestBase;
};

template<typename T>
CTestDer(T &&t) -> CTestDer<std::remove_cvref_t<T>>;

void test()
{
    CTestDer der(int{}); // OK now.
}

With a little bit more work it should be possible to:

  1. Use a variadic template in the deduction guide
  2. Have the deduction guide use decltype to construct, using its own deduction guide, the superclass
  3. Use a specialization to figure out the superclass's template parameters
  4. Use that to construct the subclass, to deduce it

This should handle anything. But this will be a lot of work. For this simple use case, and if it's not expected that the superclass will change much, this would be overkill.

Landgravine answered 30/1, 2022 at 14:50 Comment(3)
Thank you! At the end of the day, I will need to rely on knowing what constructors the base has, and define deduction guides for all of them, right? No way to get the type from Type alias of the base or something?Afb
Yes, this is what I was inferring in the second half of my question. Hopefully this explanation, and the link that I included to the reference material, should have everything that's needed to pull this off. Make it a deduction guide with a parameter pack, use decltype(CTestBase{ std::declval<Args &&>()...}), and grab its ...::Type. The End. You can give it a try, and ask a follow-up question if you run into a stumbling block. Something along these lines should work.Landgravine
You don't need to deduce a forwarding reference just to have to undo it. The other answer shows a more direct approach.Tiu
G
5

but is there a way to do without that?

Yes, just add user-defined deduction guides for CTestDer:

template<typename T>
CTestDer(T) -> CTestDer<T>;

Demo

Goosander answered 30/1, 2022 at 14:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.