C++ return different derived template class based on runtime argument

Viewed 59

I have two template class Derived1 and Derived2 both derived from Base.

I wish foo can return Derived1 or Derived2 by template instantiation and their type is distinguished by argument use_int.

class Base {
 public:
  virtual ~Base() = default;
};

template <typename T>
class Derived1 : public Base {};

template <typename T>
class Derived2 : public Base {};

template <typename Derived>
Base *foo(bool use_int) {
  if (use_int)
    return new Derived<int>();
  else
    return new Derived<float>();
}

int main() {
  Base *obj1 = foo<Derived1>(true);
  Base *obj2 = foo<Derived2>(false);
  delete obj1;
  delete obj2;
  return 0;
}

But it won't compile.

t.cc: In function ‘Base* foo(bool)’:
t.cc:12:16: error: ‘Derived’ is not a template
   12 |     return new Derived<int>();
      |                ^~~~~~~
t.cc:14:16: error: ‘Derived’ is not a template
   14 |     return new Derived<float>();
      |                ^~~~~~~
t.cc: In function ‘int main()’:
t.cc:18:34: error: no matching function for call to ‘foo<template<class T> class Derived1>(bool)’
   18 |   Base* obj1 = foo<Derived1>(true);
      |                                  ^
t.cc:10:7: note: candidate: ‘template<class Derived> Base* foo(bool)’
   10 | Base* foo(bool use_int) {
      |       ^~~
t.cc:10:7: note:   template argument deduction/substitution failed:
t.cc:19:35: error: no matching function for call to ‘foo<template<class T> class Derived2>(bool)’
   19 |   Base* obj2 = foo<Derived2>(false);
      |                                   ^
t.cc:10:7: note: candidate: ‘template<class Derived> Base* foo(bool)’
   10 | Base* foo(bool use_int) {
      |       ^~~
t.cc:10:7: note:   template argument deduction/substitution failed:

Is this because Derived1 or Derived2 is not a complete type? How can I fix this?

1 Answers

Derived1 and Derived2 are templates. If you want to use them as template arguments, you should declare Derived as template template parameter. E.g.

template <template <typename> typename Derived>
Base* foo(bool use_int) {
  if (use_int)
    return new Derived<int>();
  else
    return new Derived<float>();
}
Related