6

I have some template class that has two private static members. Users define a traits struct and provide it to the template class, which then derives from it.

Then in a c++ file the user define the static members, with one member initialized from the other. For some reason I get a "class has not been declared" error if I dont fully specify the namespace for the arg. This is only an issue when I'm in a nested namespace, there is no issue if you define the type in a single top level namespace, which makes me think this is a compiler bug. Trimmed down example below, compiling with gcc 7.2

template<typename Traits>
struct Base 
{
    static int x;
    static int y;
};

namespace foo::bar
{
    struct BarTraits
    {
    };

    using Bar = Base<BarTraits>;

    template<> int Bar::x = 0;
    template<> int Bar::y( Bar::x );  //error 
    //template<> int Bar::y( foo::bar::Bar::x ); //no error
}
François Andrieux
  • 28,148
  • 6
  • 56
  • 87
ByteMe95
  • 836
  • 1
  • 6
  • 18
  • 3
    Beware of writing questions in a way that presupposes that your question is not answerable. If your error were truly unexplainable, then there wouldn't be much point in asking about it here. – François Andrieux Feb 13 '18 at 18:13
  • 4
    [You should define them in the same namespace `Base` is defined in](https://wandbox.org/permlink/81SfSdPuhtClXVEV). Or actually borrow them from `Traits` template parameter directly. – user7860670 Feb 13 '18 at 18:17
  • 2
    Other compilers give an error already at `x`, saying *cannot define or redeclare 'x' here because namespace 'bar' does not enclose namespace 'Base'* – Bo Persson Feb 13 '18 at 18:30
  • Never confess that something "makes me think this is a compiler bug." – Jive Dadson Feb 13 '18 at 18:35
  • 1
    `template<> int Bar::y( Bar::x ); ` doesn't define a static data member with an initializer. You can't use round parentheses for an initializer here. – StoryTeller - Unslander Monica Feb 13 '18 at 18:45
  • VTT - ok I can see that, but then why doesn't int Bar::y complain without fully specifying it? – ByteMe95 Feb 13 '18 at 19:23

1 Answers1

0

According to C++ standard temp.expl.spec#3

An explicit specialization may be declared in any scope in which the corresponding primary template may be defined.

Your code violates this statement, because Bar::x and Bar::y are specialized in namespace foo::bar.

GCC incorrectly accepts first two specializations because of known defect https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56119

The following fixed code

template<typename Traits>
struct Base  {
    static int x;
    static int y;
};

struct BarTraits {};
using Bar = Base<BarTraits>;

template<> int Bar::x = 0;
template<> int Bar::y( Bar::x );

is accepted by GCC, Clang, MSVC: https://gcc.godbolt.org/z/MPxjTzbah

Fedor
  • 17,146
  • 13
  • 40
  • 131