Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
512 views
in Technique[技术] by (71.8m points)

c++ - static member initialization for specialized template class

class A
{
};

template <typename A, int S>
class B
{
public:
        static int a[S];

        B()
        {
                a[0] = 0;
        }
};

template<> int B<A, 1>::a[1];

int main()
{
        B<A, 1> t;
        t;
}

It compiles under GCC 4.1, but does not link:

static.cpp:(.text._ZN1BI1ALi1EEC1Ev[B<A, 1>::B()]+0x5): undefined reference to `B<A, 1>::a'

I would prefer to keep initialisation specialised if it is possible, since the array holds some data specific to the type.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For static member specializations, if you don't initialize the member, it is taken as a specialization declaration, that just says "Oh, don't instantiate the member from the primary template, because there is a specialized definition somewhere else". It should be mentioned that the definition should appear in a .cpp file (otherwise, you will earn the opposite: multiple definitions), and the declaration without initializer should still be placed in the header file.

Now the correct syntax is indeed the following, and it should not appear in a header file, but in a .cpp file

template<> int B<A, 1>::a[1] = { };

The following should still appear in a header file:

template<> int B<A, 1>::a[1];

This will serve as the specialization declaration.


From this, it follows that you can't specialize a member that only has a default constructor and is not copyable, because you would need this syntax:

// needs a copy constructor!
template<> Type Class<Arguments>::member = Type();

C++0x fixes this:

// doesn't anymore need a copy constructor
template<> Type Class<Arguments>::member{};

For the Standardese people among us, here are the quotes:

14.7.3/6:

If a template, a member template or the member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.

14.7.3/15:

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: there is no syntax for the definition of a static data member of a template that requires default initialization.

template<> X Q<int>::x;

This is a declaration regardless of whether X can be default initialized (8.5). ]

3.2/3:

Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required.

3.2/5:

There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (clause 14), non-static function template (14.5.5), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.4) in a program [...]

The restriction of this to "for which some template parameters are not specified" means that we are allowed to do the following, placing it into a header (thus possibly having multiple definitions of this specialization):

template<> template<typename T>
Type OuterClass<int>::InnerClass<T>::StaticMember = 0;

In your case, you have all parameters specified, making it not being covered by the one defintion rule for allowing multiple definitions.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...