简体   繁体   中英

Deduce types of template-defined base class constructor parameters

I have a derived class, Wrapper , that inherits from a template-defined base class. I'd like to configure Wrapper so that if the base class has constructor parameters, Wrapper 's constructor also includes the base class's constructor params so that it can forward them to the base class constructor:

struct Base1 {
  Base1(int) {}
};

struct Base2 {
  Base2(std::string) {}
};

// I'd like variadic template param `Args` to be deduced to a parameter
// pack matching a valid constructor for type T, if available.
template <typename T, typename... Args>
struct Wrapper : public T {
  Wrapper(int, Args&&... v) : T(std::forward<Args>(v)...) {}
};

int main() {
  auto wrapper = Wrapper<Base1>(1, 2);
}

This example fails because the compiler is not deducing anything for Args , and so the resulting error is:

no matching function for call to ‘Wrapper<Base1>::Wrapper(int, int)’:
  candidate: ‘Wrapper<T, Args>::Wrapper(int, Args&& ...) [with T = Base1; Args = {}]’
  candidate expects 1 argument, 2 provided

Is it possible to force the compiler to deduce the type(s) for the variadic template parameter Args , based on the deduced value of T and the parameters provided to Wrapper at construction?

Instead of having Args as a template parameter pack of the class template, you can make the constructor a template as shown below:

//------------------v--------------->removed Args from here
template <typename T >
struct Wrapper : public T {
//--vvvvvvvvvvvvvvvvvvvvvvvvvv----->made this a templated ctor
    template<typename... Args>
    Wrapper(int, Args&&... v) : T(std::forward<Args>(v)...) {}
};

int main() {
  auto wrapper = Wrapper<Base1>(1, 2); //works now
}

Working demo

The behavior you are looking for is Partial CTAD(Class Template Argument Deduction) . At the moment, such behavior is not allowed in C++, and you must either provide all template parameters, or none.

For more relevant informations: Partial class template argument deduction in C++17


A common pattern is to create a make_XXX function that will deduce the return type for you:

template<typename T, typename ... Args>
auto make_wrapper(int, Args&& ... args)
{
    return Wrapper<T>(std::forward<Args>(args)...);
}

And you will be able to call it like:

auto wrapper = make_wrapper<Base1>(1, 2);

Here wrapper will be a Wrapper<Base1, int> .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM