Search code examples
c++templatespolymorphismderived-class

Template class implementation has compilation issues


I am creating an object using static member function of a class. and then calling a function inside.

int main(){
  int a = 49;
  auto foo = Foo::createFoo(a);

  foo->study();
}

Implementation
for this example lets have study() display a value.
Structure wise I do have constraints to have the below interface and then the static method returning the object

class I_Foo{
public:
  virtual void study(void) = 0;
};

class Foo : public I_Foo{
public:
  static Foo* createFoo(int x_) {
    return new Foo(x_);
  }
  
  void study() override{
    std::cout << "studied: "<< st << std::endl;
  }

protected:
  Foo(int a) : st(a) {}

  int st = 0;
};

This above implementation is absolutely working good and as expected i.e., variable a should be displayed as studied: a

Now I want to change the behaviour of this
Lets say for values below 50, the above implementation should remain "unchanged" i.e., variable a should be displayed as studied: a
However as the value becomes 50 and above then the output should display studied: a+100


#include <iostream>

class I_Foo{
public:
  virtual void study(void) = 0;
};

template<int>
class FooImpl;

class Foo : public I_Foo {
public:
  static Foo* createFoo(int x_) {
    
    Foo* foo = nullptr;
    if (x_>=50) {
        foo = new FooImpl<2>(x_);
    }
    else {
        foo = new FooImpl<1>(x_);
    }
    return foo;
  }
};

template<int FT = 1>
class FooImpl : public Foo{
public:

  void study() override{
    std::cout << "studied: "<< st << std::endl;
  }

  FooImpl(int a) : st(a) {}

  int st = 0;
};

template<>
void FooImpl<2>::study() override{
  std::cout << "studied: "<< st + 100 << std::endl;
}

int main()
{
  int a = 56;
  auto foo = Foo::createFoo(a);

  foo->study();
}

This obviously doesnot compile as the Foo has no clue what FooImpl is!

Please suggest how can I make this work. The requirement is to keep the main function untouched but have the new functionality.

Please note Yes, I know this could be solved by if statement, but that is not the point. It has a complex implementation in reality I just tried to present it in a fairly understandable problem to study how these templates could work.

EDIT 1
After first editt I seeing the below compliation error abc


Solution

  • As I wrote in the comment: Do not implement createFoo function inside the class declaration.

    #include <iostream>
    
    class I_Foo {
    public:
      virtual void study(void) = 0;
    };
    
    class Foo : public I_Foo {
    public:
      // here just DECLARE the method...
      static Foo *createFoo(int x_);
    };
    
    /********/
    /* SNIP */
    /********/
    
    // ...and IMPLEMENT it there
    Foo *Foo::createFoo(int x_) {
        if (x_>=50) { 
          return new FooImpl<2>(x_);
        } else {
          return new FooImpl<1>(x_);
        }
    }
    
    int main() {
      int a = 56;
      auto foo = Foo::createFoo(a);
    
      foo->study();
    }