6

I'm trying to figure out why this example doesn't compile. My understanding is that if a static variable is not explicitly set then it defaults to 0. In the five examples below four of them behave as I would expect, but the one that's commented out won't compile.

#include <iostream>
class Foo
{
public:
    static int i;
    static int j;
};
template <int n>
class Bar
{
public:
    Bar(int) { }
    static int i;
}; 

static int i;
int Foo::i;
int Foo::j = 1;
template <> int Bar<2>::i;
template <> int Bar<3>::i = 3;

int main(int argc, char** argv)
{
    std::cout << "i         " << i << std::endl;
    std::cout << "Foo::i    " << Foo::i << std::endl;
    std::cout << "Foo::j    " << Foo::j << std::endl;
    //std::cout << "Bar<2>::i " << Bar<2>::i << std::endl; // Doesn't compile?
    std::cout << "Bar<3>::i " << Bar<3>::i << std::endl;
    return 0;
}

Why doesn't int Bar<2>::i do the same thing as int Foo::i or static int i?

Edit: I had forgotten to add template<> to the Bar<2> and Bar<3> declarations. (doesn't solve the problem though, still getting linker errors)

Alex
  • 14,973
  • 13
  • 59
  • 94
  • 3
    Duplicate of [static member initialization for specialized template class](http://stackoverflow.com/questions/2342550/static-member-initialization-for-specialized-template-class). – James McNellis Sep 08 '10 at 05:27
  • @Chubsdad: Undoubtedly it is "Undefined reference to `Bar<2>::i`" or something meaning that. In the OP's code, `template<> int Bar<2>::i;` is a _nondefining_ declaration (see the linked duplicate for litb's detailed explanation). – James McNellis Sep 08 '10 at 05:37
  • I'm not quite following litb's answer as the code is slightly different in the other case. Is he saying that I must explicitly set Bar<2>::i in order to use it? If at all possible I'd like to be able to declare it without having to explicitly set it. – Alex Sep 08 '10 at 05:46
  • 14.7/1: _The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, *static data members* and member templates; and it causes the implicit instantiation of the definitions of member anonymous unions._ This is probably what is going on. (Emphasis mine.) – dirkgently Sep 08 '10 at 05:50
  • @Alex: Right: You must provide an initializer for it to be a definition. Otherwise, it's just a declaration. – James McNellis Sep 08 '10 at 05:56
  • Dang. Then what I wanted to do isn't possible. It sucks that it doesn't initialize it to 0 like the other declarations do. That foils what I wanted to do. Thanks for the help. – Alex Sep 08 '10 at 06:01
  • @Alex: Other data declarations also don't. You have to intialize them explicity in the constructor – Chubsdad Sep 08 '10 at 06:25
  • `int Foo::i` does exactly what I want `template<> Bar<2>::i` to do; it initializes it to 0 but I'm still free to define it later in the file. Basically what I'm trying to do is make a templated class and make a macro like SET_DEFAULTS(type). the macro would simply declare all of the static members, which would initialize it to zero if it weren't templated, but the user could override whichever ones they wanted manually. If I have to set it to 0 in my macro, then the compiler complains when they try to redefine it, so I need to find a different solution. – Alex Sep 08 '10 at 06:44

2 Answers2

5

Under the rules of the current C++ standard, the specialisation template <> int Bar<2>::i; is only a declaration and never a definition. To become a definition, you must specify an initialiser. (See clause 14.7.3/15)

Apart from that, you were missing one very common case: the definition of a non-specialised static member of a template:

template <int n> int Bar<n>::i;

This provides a definition for Bar<N>::i for N not equal to 2 or 3.

Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41
1

According to the latest draft of Standard C++ it says

14.7.3/13 An explicit specialization of a static data member of a template is a definition if the declaration includes an initializer; otherwise, it is a declaration.
[Note: the definition of a static data member of a template that requires default initialization must use a braced-init-list:

 template<> X Q<int>::x;       //declaration
 template<> X Q<int>::x ();    // error: declares a function
 template<> X Q<int>::x { };   // definition

— end note ]

So what you are asking is possible, if your compiler is supporting it.

aeh
  • 779
  • 5
  • 8