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: ‘Derived<T, Args>::Derived(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?
CodePudding user response:
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>
.
CodePudding user response:
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
}