danharel
danharel

Reputation: 15

Declaring a member template function with the same template type as class

I have a class that I want to initialize this class using a factory function of the template type. It also needs to depend on a long-lasting dependency that I want to store as member variables and refer to in the factory functions. E.g.

template <class T>
class Foo {
 public:
  Foo() : member_(Create<T>()) {}

  template <class T>
  T Create();

 private:
  T member_;

  SomeType* dependency_a_;
  OtherType* dependency_b_;
};

template <>
TypeA Foo<TypeA>::Create<TypeA>() {
  return TypeA(dependency_a_);
}

template <>
TypeB Foo<TypeB>::Create<TypeB>() {
  return TypeB(dependency_b_);
}

In the current state, I'm getting the following error:

template_example.cc:17:19: error: declaration of 'T' shadows template parameter
  template <class T>
                  ^
template_example.cc:12:17: note: template parameter is declared here
template <class T>
                ^
template_example.cc:28:19: error: template specialization requires 'template<>'
TypeA Foo<TypeA>::Create<TypeA>() {
                  ^     ~~~~~~~
template_example.cc:33:19: error: template specialization requires 'template<>'
TypeB Foo<TypeB>::Create<TypeB>() {

I don't have much experience with templates, so I'm not really sure what the template for Create should look like (or even if it should have a template). I've tried a number of combinations of different things, and they all get compiler errors.

Any idea how to do what I want to do? The one thing I can think of is to pass all dependencies to Create. Then it doesn't need to be a member function anymore. But then anyone who adds a new factory function needs to remember to add to the Create signature. It wouldn't be the end of the world, but I'd like to know if there's a solution that doesn't require that.

Upvotes: 0

Views: 935

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 598134

There is no need to have a template on Create() at all, since it is already on Foo. Just have Create() use Foo's own T template parameter as-is, just as you are with member_, eg:

template <class T>
class Foo {
 public:
  Foo() : member_(Create()) {} // <T> not needed here!

  T Create(); // no 'template' here!

 private:
  T member_;

  SomeType* dependency_a_;
  OtherType* dependency_b_;
};

template <class T>
T Foo<T>::Create() {
  return T();
}

template <>
TypeA Foo<TypeA>::Create() {
  return TypeA(dependency_a_);
}

template <>
TypeB Foo<TypeB>::Create() {
  return TypeB(dependency_b_);
}

Upvotes: 2

Related Questions