0
class Base {
public:
    template<typename T>
    static Base* construct() {
        return new Derived<T>();
    }
};

template<typename T>
class Derived : public Base {
public:
    Derived() {}
};

That code generates a compile error (VS Studio 2017):

syntax error: unexpected token 'identifier', expected 'type specifier'

Is this invalid C++? Is this pattern not possible?

jkdev
  • 11,360
  • 15
  • 54
  • 77
Nico van Bentum
  • 339
  • 1
  • 13
  • see https://stackoverflow.com/questions/4757565/what-are-forward-declarations-in-c –  Aug 11 '19 at 02:05
  • While you may be slightly different because of the template part of your question, the answers are pretty close to thos found at [Resolve build errors due to circular dependency amongst classes](https://stackoverflow.com/questions/625799/resolve-build-errors-due-to-circular-dependency-amongst-classes). Thus, I'm flagging as a duplicate. –  Aug 11 '19 at 02:07

3 Answers3

5

Declare Base as:

class Base {
public:
    template<typename T>
    static Base* construct();
}

Then declare Derived:

template<typename T>
class Derived : public Base {
public:
    Derived() {}
};

Then define Base::construct:

static Base* Base::construct() {
    return new Derived<T>();
}

The compiler needs a full definition of Derived before it can deal with the new in Base::construct.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
0

Try forward declare class Derived before Base.

template <typename T>
class Derived;

class Base {
//...
}; 

The compiler doesn't know what is Derived in return new Derived<T>() as it is declared afterwards. `

idailylife
  • 174
  • 2
  • 14
  • 2
    You can only have things like pointers for forward declared classes, not `new` statements. It needs to know the `sizeof` for starters. – Paul Evans Aug 11 '19 at 01:07
0

Either split the declaration and implementation:

class Base {
public:
    static Base* construct();
};

template<typename T>
class Derived : public Base {
public:
    Derived() {}
};

template<typename T>
Base* Base::construct() {
    return new Derived<T>();
}

Or use the template magic:

template<typename Derived>
class Base {
public:
    static Base* construct() {
        return new Derived();
    }
};

template<typename T>
class Derived : public Base<Derived<T>> {
public:
    Derived() {}
};
273K
  • 29,503
  • 10
  • 41
  • 64