Question

I'm having problems declaring an incomplete struct inside a class specialization and later defining it.

struct Foo {
    template <bool Y, typename D>
    struct Bar {};

    template <typename D>
    struct Bar<true, D> {
        struct Qux;
    };

    template <typename D>
    struct Bar<true, D>::Qux { int x; };
};

This code works in gcc, but fails in clang 3.3:

r.cpp:42:26: error: non-friend class member 'Qux' cannot have a qualified name
    struct Bar<true, D>::Qux { int x; };
           ~~~~~~~~~~~~~~^

If the code is written in namespace scope (without struct Foo), it works in clang too.

On the other hand, if struct Foo is turned into a template, as follows, the code breaks in gcc-4.9 (unreleased), though it keeps working in gcc-4.7.

template <typename X>
struct Foo {
    template <bool Y, typename D>
    struct Bar {};

    template <typename D>
    struct Bar<true, D> {
        struct Qux;
    };

    template <typename D>
    struct Bar<true, D>::Qux { int x; };
};

Clang fails with:

r.cpp:43:26: error: template specialization or definition requires a template parameter list corresponding to the nested type 'Bar<true, type-parameter-1-0>'
    struct Bar<true, D>::Qux { int x; };
                         ^
r.cpp:43:26: error: non-friend class member 'Qux' cannot have a qualified name
    struct Bar<true, D>::Qux { int x; };
           ~~~~~~~~~~~~~~^
2 errors generated.

Gcc-4.9 fails with a similar error:

r.cpp:43:26: error: too few template-parameter-lists
     struct Bar<true, D>::Qux { int x; };
                          ^
Was it helpful?

Solution

Looks like you don't have a choice but to put that definition in namespace scope (or inside Bar). Paragraph 9/1 (n3337) says your code is illegal:

If a class-head-name contains a nested-name-specifier, the class-specifier shall refer to a class that was previously declared directly in the class or namespace to which the nested-name-specifier refers, or in an element of the inline namespace set (7.3.1) of that namespace (i.e., not merely inherited or introduced by a using-declaration), and the class-specifier shall appear in a namespace enclosing the previous declaration. In such cases, the nested-name-specifier of the class-head-name of the definition shall not begin with a decltype-specifier.

OTHER TIPS

struct Foo {
  template <bool Y, typename D>
  struct Bar {};
};

template <typename D>
struct Foo::Bar<true, D> {
  struct Qux;
};

template <typename D>
struct Foo::Bar<true, D>::Qux {
  int x;
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top