Search code examples
c++templatessfinaectad

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?


Solution

  • 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