Bug 11585 - static template member definition fails
Summary: static template member definition fails
Status: RESOLVED DUPLICATE of bug 17445
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.4.0
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2003-07-19 00:00 UTC by Dirk Mueller
Modified: 2005-07-23 22:49 UTC (History)
2 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dirk Mueller 2003-07-19 00:00:44 UTC
Hi,  
 
this testcase stopped compiling with current mainline: 
 
=== Cut === 
template<typename T> class A { static int n; }; 
int A<int>::n = 0; 
=== Cut === 
 
$ g++ -Wall -c templ.cc 
templ.cc:2: error: too few template-parameter-lists 
templ.cc:2: error: expected `,' or `;' 
 
above compiles fine with any older gcc version. I don't see what could be wrong 
with it, therefore I assume its a compiler bug.
Comment 1 Andrew Pinski 2003-07-19 00:09:41 UTC
I cannot comment on if this is valid but using Phil's regression hunter: Search converges between 
2002-12-27-trunk (#177) and 2002-12-28-trunk (#178) so it is caused by the new parser.
Comment 2 Andrew Pinski 2003-07-19 00:11:16 UTC
I found a workaround (if the code given in the bug is not valid, then this is the right thing to do):
template<typename T> class A { static int n; };
template<> int A<int>::n = 0;
Comment 3 Dara Hazeghi 2003-07-19 00:24:38 UTC
FWIW, the edg front-end thinks its valid.
Comment 4 Dirk Mueller 2003-07-19 00:28:13 UTC
ah, the workaround looks interesting. so it could be a bug in the code after 
all. Hmm, feel free to close if this is invalid C++.  
Comment 5 Wolfgang Bangerth 2003-07-19 02:25:09 UTC
gcc is right, the code is illegal. You need to prefix explicit specializations
with "template <>".

W.
Comment 6 Jaco Kroon 2005-02-26 10:03:21 UTC
A more complex example, this code works with gcc 3.3 so this imho is either
incorrect code or a bug in the new parses:

template <class T> class FakeList {
public:
        void foo() {};
};

template <class T> class Factory {
public:
        typedef T* (*CreateType)();
        typedef struct { char *name; CreateType creator; } TypePair;
        static FakeList<TypePair> _types;

        T* createOne() {
                _types.foo();
                return 0;
        };
};

typedef Factory<int> IntFactory;

/*
 * I've tried prefixing this with template <>
 * which them compiles, but fails to link.
 */
FakeList<IntFactory::TypePair> IntFactory::_types;

int main(int, char**) {
        IntFactory blah;
        blah.createOne();

        return 0;
}

I'm using gcc 3.4.3 on amd64.
Comment 7 Giovanni Bajo 2005-02-27 00:02:49 UTC
This is still incorrect code. You need an explicit template<> before that 
line. Though, after that, I cannot see why it should fail to link. What is the 
link error? That is a possible bug in GCC.
Comment 8 Jaco Kroon 2005-02-27 06:17:03 UTC
$ g++ -o templates templates.C -Wall
/tmp/ccoANWiL.o(.gnu.linkonce.t._ZN7FactoryIiE9createOneEv+0xd): In function
`Factory<int>::createOne()':
: undefined reference to `Factory<int>::_types'
collect2: ld returned 1 exit status
Comment 9 Giovanni Bajo 2005-02-27 09:03:15 UTC
Ah no, then it is ok. When you write:

template<>
FakeList<IntFactory::TypePair> IntFactory::_types;

you are actually *declaring* a specialization of _types. A declaration is not 
a definition, so the linker complains. To mutate this into a definition you 
need to disambiguate the statement by adding an explicit constructor. For 
instance:

template<>
FakeList<IntFactory::TypePair> IntFactory::_types = 
FakeList<IntFactory::TypePair>();

In this way, the declaration of the specialization is also a definition, and 
the code compiles and links correctly.

But are you sure you want to declare a specialization of the static member in 
the first place? Probably you just want to define the static member for all 
the possible instantiations. In this case, the syntax is much easier:

template <class T>
FakeList<typename Factory<T>::TypePair> Factory<T>::_types;

and you don't need to repeat this for IntFactory, FloatFactory, 
WhateverFactory.

For more information, please consult a good book about C++ templates or ask 
somewhere else (comp.lang.c++.moderated, for instance).


Comment 10 Jaco Kroon 2005-02-27 19:25:48 UTC
Ok.  The only reason I found this was cause I tried to compile quasar on my
system.  The code I supplied was the most reduced form I could create that
duplicated the problem.  As such I will attempt to make the smallest number of
changes to the system (there is about 4 of these so I'll just go with the
explicit instantiation for each as this is the way it currently works).

The "cover all cases" definition will need to be in the header file though
right?  Won't this produce duplicate symbols?  Or will the linked automatically
know to consolidate all these different symbols in the different object files
into the same symbol in the produced executable?

Yes, I was aware of the declaration vs definition problem (The book I learned
C++ from explained this quite well), but I'm by no means a template guru, in
fact, very far from (I use them in basic ways usually, even when using the STL).

I was actually quite surprised that the compiler moaned in the first place, and
was a bit skeptical about adding template <> cause that just felt/looked like a
declaration and not a definition.

Oh, and yes, the solution provided does work.  Thank you very much for your help.

One thing is sure though, I don't see the ambiguity between the statement with 

template<> ...::_types;

and

template <> ...::_types = ...;

Both in my opinion is quite clearly a definition.  We are defining that
variable, for IntFactory, which as far as I can tell, is no longer really a
template - why the template<> still?  Someone explained to me that it is,
actually, still a template, but doesn't take any more parameters (it's a
specialisation of the template - this much makes sense).  But as we are defining
the _types static attribute, this is no longer a specialization - why is the
template<> prefix still required?  After all, it is simply a variable.  I guess
I just need to go and think about this for a bit to wrap my mind around it.

Once again:  Thanks.
Comment 11 Andrew Pinski 2005-04-25 04:10:46 UTC
Reopening to ...
Comment 12 Andrew Pinski 2005-04-25 04:11:12 UTC
To mark as a dup of bug 17445.

*** This bug has been marked as a duplicate of 17445 ***