0

I'm trying to understand why the following code snippet will not compile:

template <class Derived> struct Base {
    const std::set<typename Derived::Foo> types() const { return theSet; }
    std::set<typename Derived::Foo> theSet;
};

struct Derived : Base<Derived> {
    enum Foo { X,Y,Z };
};

int main(int argc, char** argv) { Derived x; return 0; }

I get an error saying that the the line with types() const is an invalid use of incomplete struct Derived - but all it needs to know is that the type of the set is a Foo enum so I'm not sure I understand the error or if there's a way around it that doesn't require me to make that set of type int..

The full error from the compiler says:

error: invalid use of imcomplete type 'struct Derived'
    const std::set<typename Derived::Foo> types() const {
error: forward declaration of 'struct Derived'
struct Derived : Base<Derived>
Palace Chan
  • 8,845
  • 11
  • 41
  • 93
  • Always helpful to include the actual error message in your post – Captain Obvlious Jun 14 '17 at 19:18
  • I suppose that when compiler tries to instantiate Derived class it sees that it is derived from Base and instatiates it. But at this moment Derived isn't fully instantiated so compiler doesn't know what the type Derived::Foo is (the std::set can't be instantiated with incomplete template parameter). – Dmitry Gordon Jun 14 '17 at 19:54
  • @DmitryGordon is there a simple way around this? I fear I might have to make the set be of ints... – Palace Chan Jun 14 '17 at 20:01
  • @CaptainObvlious added it – Palace Chan Jun 14 '17 at 20:03
  • Don't use the same name for a template parameter and an external type. Are you sure you're showing us the whole code? – John Jun 14 '17 at 20:39
  • @Palace Chan I see only one solution - make the enum template parameter, same as Yatima suggests – Dmitry Gordon Jun 15 '17 at 06:13

1 Answers1

0

To compile this example compiler will need a forward declaration for nested type which does not seems to be possible (see How do I forward declare an inner class?) so simplest workaround might be to make Base class to take two templates and move Foo out of your class definition:

#include <set>

template <class T, typename F> struct Base
{
    const std::set<F> types() const { return theSet; }
    std::set<F> theSet;
};

enum class Foo { X,Y,Z };

struct Derived : Base<Derived, Foo>
{
};

int main(int argc, char** argv)
{
    Derived x; return 0;
}
Yatima
  • 119
  • 7