Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Multiple definition and specialization of static data member

152 views
Skip to first unread message

Wu Yongwei

unread,
May 6, 2006, 1:20:21 PM5/6/06
to
I posted the following message days ago to comp.std.c++, and got an
helpful answer from Alberto Ganesh Barbati. However, I would like to
hear more comments from you gurus here, esp. whether the behaviour of
MSVC 8 is standard conforming, best with quotations from the Standard.

-------------------------------

I encountered a problem in a header file like the following:

template <typename DataType>
class FMC
{
public:
static DataType Epsilon;
private:
FMC() {}

};

template <typename DataType>
DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);

template <>
double FMC<double>::Epsilon = static_cast<double>(0.0000000001);

When multiple .cpp files include this header file, GCC 3.4.4 (or some
earlier version) will complain:

...: multiple definition of `FMC<double>::Epsilon'
...

To make GCC work, I have to reorganize the header file as follows:

- In header file

template <typename DataType>
class FMC
{
public:
static DataType Epsilon;
private:
FMC() {}

};

template <typename DataType>
DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);

template <>
double FMC<double>::Epsilon;

- In another .cpp file

#include "fmc.h"

template <>
double FMC<double>::Epsilon = static_cast<double>(0.0000000001);

However, then MSVC 8 will choke and declare that the definition in the
.cpp file is a redefinition. It works with the original version.

My question is, which way is the standard-conforming way? and which
compiler is standard conformant on this issue?

Best regards,

Yongwei


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Greg Herlihy

unread,
May 8, 2006, 8:47:59 AM5/8/06
to
Wu Yongwei wrote:
> I posted the following message days ago to comp.std.c++, and got an
> helpful answer from Alberto Ganesh Barbati. However, I would like to
> hear more comments from you gurus here, esp. whether the behaviour of
> MSVC 8 is standard conforming, best with quotations from the Standard.
>
> -------------------------------
>
> I encountered a problem in a header file like the following:
>
> template <typename DataType>
> class FMC
> {
> public:
> static DataType Epsilon;
> private:
> FMC() {}
>
> };
>
> template <typename DataType>
> DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);


This is the definition of Epsilon, a static data member of the class
template FMC. Placing this definition in a header file is likely to
prove problematic and for the reasons described. Essentially every
source file that instantiates Epsilon will also define it - leading to
a multiply-defined symbol error at link time.


> template <>
> double FMC<double>::Epsilon = static_cast<double>(0.0000000001);


This statement is an explicit specialization for Epsilon when FMC is
instantiated with the type double. Note that the presence of an
initializer for Epsilon makes this statement a definition - and not a
declaration - of the explicit specialization. Once again, placing a
definition in a header file is bound to to lead a multiply-defined
symbol error if more than one file references FMC<double>::Epsilon.


> When multiple .cpp files include this header file, GCC 3.4.4 (or some
> earlier version) will complain:
>
> ...: multiple definition of `FMC<double>::Epsilon'
> ...
>
> To make GCC work, I have to reorganize the header file as follows:
>
> - In header file
>
> template <typename DataType>
> class FMC
> {
> public:
> static DataType Epsilon;
> private:
> FMC() {}
>
> };
>
> template <typename DataType>
> DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);


Well, this definition staying in the header file can mean only one
thing: and that is that we probably have not seen the last of the
multiply-defined symbol error.


> template <>
> double FMC<double>::Epsilon;


This line in contrast has changed - and changed for the better.
Removing the initializer has transformed an explicit specialization
definition into an explicit specialization declaration. And the
declaration has the opposite affect of the definition. It inhibits the
instantiation of the FMC<double>::Epsilon in source files that
reference it - unless that source file has FMC<double>::Epsilon's
definition. So moving the definition of the explicit specialization
into a source file ensures that the program defines the static data
member only once - no matter how many source files actually reference
it.


> - In another .cpp file
>
> #include "fmc.h"
>
> template <>
> double FMC<double>::Epsilon = static_cast<double>(0.0000000001);
>
> However, then MSVC 8 will choke and declare that the definition in the
> .cpp file is a redefinition. It works with the original version.
>
> My question is, which way is the standard-conforming way? and which
> compiler is standard conformant on this issue?


Before we can judge the compilers, we need to get the program into a
working state. And the structure of this program as we last left it,
has only a very limited fix for the Epsilon's multiple definition
problem. In fact it only works in one particular Epsilon - the Epsilon
for FMC<double>.

So as matters stand, if the program tries to instantiate FMC with a
type other than double, and then references that template's Epsilon in
more than once source file - than the exact same problem would happen
again. And in fact I would bet it is exactly this re-emergence that
explains why MSVC 8 failed to compile. Especially since the error as
you originally posted in comp.std.c++ mentioned FMC<float> explicitly -
which is exactly the kind of type that we know would trigger the error
reported.

The all-around fix is to move Epsilon's general template definition out
of the header file completely and into one of the source files. The
general class template Epsilon is already declared by FMC's class
template declaration; so all that the program has left to do is to
define it - and to define it once and one time only. And moving the
definition into a source file will achieve precisely that effect.

Greg

VSR

unread,
May 8, 2006, 3:25:21 PM5/8/06
to
I am sorry, not had my coffee yet this morning. but at first look, I do
not see any problem with the compiler.

> However, then MSVC 8 will choke and declare that the definition in the
> .cpp file is a redefinition. It works with the original version.

well you are redefining the variable and *all* C++ compilers should
crib about that. Its not about standards, it is about syntax.

templates are designed to be generic and static variables are by design
'fixed'. so I would feel uncomfortable using statics with template
classes unless I really have to use them.

in your case, you can get rid of the definitions of the static from
your header and move all of it to your client cpp file. Not a perfect
solution but will work.

Maxim Yegorushkin

unread,
May 8, 2006, 3:37:27 PM5/8/06
to

Wu Yongwei wrote:
> I posted the following message days ago to comp.std.c++, and got an
> helpful answer from Alberto Ganesh Barbati. However, I would like to
> hear more comments from you gurus here, esp. whether the behaviour of
> MSVC 8 is standard conforming, best with quotations from the Standard.
>
> -------------------------------
>
> I encountered a problem in a header file like the following:
>
> template <typename DataType>
> class FMC
> {
> public:
> static DataType Epsilon;
> private:
> FMC() {}
>
> };
>
> template <typename DataType>
> DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);
>
> template <>
> double FMC<double>::Epsilon = static_cast<double>(0.0000000001);
>
> When multiple .cpp files include this header file, GCC 3.4.4 (or some
> earlier version) will complain:
>
> ...: multiple definition of `FMC<double>::Epsilon'
> ...

Static data members of class templates are an exempt from One
Definition Rule [3.2/5], this is why you can define the static member
in the header file without getting a multiple definitions error.

OTOH, full specialization is not a template so that the exempt does not
apply here, this is why you get the error when you put the full
specialization of the static member in the header.

Nicola Musatti

unread,
May 8, 2006, 3:50:07 PM5/8/06
to

Greg Herlihy wrote:
[...]

> The all-around fix is to move Epsilon's general template definition out
> of the header file completely and into one of the source files. The
> general class template Epsilon is already declared by FMC's class
> template declaration; so all that the program has left to do is to
> define it - and to define it once and one time only. And moving the
> definition into a source file will achieve precisely that effect.

I'm not convinced this would work, unless that one source file happened
to contain code that caused all the needed specializations of the
static member to be instantiated. If this were treally necessary it
would be more practical and less error prone to explictly instantiate
the static member for every needed specialization.

Cheers,
Nicola Musatti

Seungbeom Kim

unread,
May 8, 2006, 3:51:22 PM5/8/06
to
Greg Herlihy wrote:

> Wu Yongwei wrote:
>>
>> I encountered a problem in a header file like the following:
>>
>> template <typename DataType>
>> class FMC
>> {
>> public:
>> static DataType Epsilon;
>> private:
>> FMC() {}
>>
>> };
>>
>> template <typename DataType>
>> DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);
>
> This is the definition of Epsilon, a static data member of the class
> template FMC. Placing this definition in a header file is likely to
> prove problematic and for the reasons described. Essentially every
> source file that instantiates Epsilon will also define it - leading to
> a multiply-defined symbol error at link time.

But isn't it how templates work? Everything is defined in the header,
and instantiation of the same template with the same parameters in
multiple source files will be handled appropriately by the linker.
Not only for the objects, but for the functions as well.

--
Seungbeom Kim

Maxim Yegorushkin

unread,
May 9, 2006, 8:13:43 AM5/9/06
to

Greg Herlihy wrote:
> Wu Yongwei wrote:
> > I posted the following message days ago to comp.std.c++, and got an
> > helpful answer from Alberto Ganesh Barbati. However, I would like to
> > hear more comments from you gurus here, esp. whether the behaviour of
> > MSVC 8 is standard conforming, best with quotations from the Standard.
> >
> > -------------------------------
> >
> > I encountered a problem in a header file like the following:
> >
> > template <typename DataType>
> > class FMC
> > {
> > public:
> > static DataType Epsilon;
> > private:
> > FMC() {}
> >
> > };
> >
> > template <typename DataType>
> > DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);
>
>
> This is the definition of Epsilon, a static data member of the class
> template FMC. Placing this definition in a header file is likely to
> prove problematic and for the reasons described. Essentially every
> source file that instantiates Epsilon will also define it - leading to
> a multiply-defined symbol error at link time.

This explanation sounds completely wrong to me. I think the standard is
pretty clear on this subject:

[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 provided that each definition appears in a different
translation unit, and provided the definitions satisfy the following
requirements...

Alberto Ganesh Barbati

unread,
May 9, 2006, 8:25:40 AM5/9/06
to
VSR ha scritto:

> I am sorry, not had my coffee yet this morning. but at first look, I do
> not see any problem with the compiler.
>
>> However, then MSVC 8 will choke and declare that the definition in the
>> .cpp file is a redefinition. It works with the original version.
>
> well you are redefining the variable and *all* C++ compilers should
> crib about that. Its not about standards, it is about syntax.

As you are not quoting the source, it's not clear what variable are you
talking about. If you are talking about double FMC<double>::Epsilon in
the *second* example, then your remark is wrong, because the line:

template <>
double FMC<double>::Epsilon;

is a declaration, not a definition 14.7.3/15.

> templates are designed to be generic and static variables are by design
> 'fixed'. so I would feel uncomfortable using statics with template
> classes unless I really have to use them.

class templates can have static members. I see nothing wrong with it and
I know a lot of useful idioms and use-cases that uses them. I don't
understand your feeling uncomfortable. Could you please clarify?

> in your case, you can get rid of the definitions of the static from
> your header and move all of it to your client cpp file. Not a perfect
> solution but will work.

I don't see how the OP could get rid of those definitions while keeping
the same semantic. Could you show us the code you have in mind, please?

Ganesh

Alberto Ganesh Barbati

unread,
May 9, 2006, 8:24:08 AM5/9/06
to
Greg Herlihy ha scritto:

>> template <typename DataType>
>> DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);
>
> This is the definition of Epsilon, a static data member of the class
> template FMC. Placing this definition in a header file is likely to
> prove problematic and for the reasons described. Essentially every
> source file that instantiates Epsilon will also define it - leading to
> a multiply-defined symbol error at link time.

This is plain wrong. As the programmer clearly intend to rely on
implicit instantiation of Epsilon when DataType != double then the
"generic" definition must be put in the header, as it needs to be
included in all compilation units that may potentially use it. There is
nothing wrong with more than one compilation unit trying to implicitly
instantiate Epsilon, that's how templates work. In fact, the observable
behavior is that there's only one instantiation, although there may be
multiple instantiation points (see 14.6.4.1/7 for reference).

>> template <>
>> double FMC<double>::Epsilon = static_cast<double>(0.0000000001);
>
> This statement is an explicit specialization for Epsilon when FMC is
> instantiated with the type double. Note that the presence of an
> initializer for Epsilon makes this statement a definition - and not a
> declaration - of the explicit specialization. Once again, placing a
> definition in a header file is bound to to lead a multiply-defined
> symbol error if more than one file references FMC<double>::Epsilon.

This is correct, because having more than one explicit specialization
with the same template parameters makes the program ill-formed.

>> template <typename DataType>
>> DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);
>
> Well, this definition staying in the header file can mean only one
> thing: and that is that we probably have not seen the last of the
> multiply-defined symbol error.

Again, this is wrong.

>> template <>
>> double FMC<double>::Epsilon;
>
> This line in contrast has changed - and changed for the better.
> Removing the initializer has transformed an explicit specialization
> definition into an explicit specialization declaration. And the
> declaration has the opposite affect of the definition. It inhibits the
> instantiation of the FMC<double>::Epsilon in source files that
> reference it - unless that source file has FMC<double>::Epsilon's
> definition. So moving the definition of the explicit specialization
> into a source file ensures that the program defines the static data
> member only once - no matter how many source files actually reference
> it.

This is also correct.

> Before we can judge the compilers, we need to get the program into a
> working state. And the structure of this program as we last left it,
> has only a very limited fix for the Epsilon's multiple definition
> problem. In fact it only works in one particular Epsilon - the Epsilon
> for FMC<double>.

I disagree. The code looks perfectly legal to me. The fact that VC8
doesn't compile it looks like a bug to me. g++ agrees with me.

> The all-around fix is to move Epsilon's general template definition out
> of the header file completely and into one of the source files. The
> general class template Epsilon is already declared by FMC's class
> template declaration; so all that the program has left to do is to
> define it - and to define it once and one time only. And moving the
> definition into a source file will achieve precisely that effect.

The problem is that moving the definition of Epsilon in the source file
still doesn't work with VC8 and that was exactly what the OP was trying
to say.

Ganesh

Wu Yongwei

unread,
May 9, 2006, 4:04:35 PM5/9/06
to
Greg Herlihy wrote:

> Wu Yongwei wrote:
> > I posted the following message days ago to comp.std.c++, and got an
> > helpful answer from Alberto Ganesh Barbati. However, I would like to
> > hear more comments from you gurus here, esp. whether the behaviour of
> > MSVC 8 is standard conforming, best with quotations from the Standard.
> >
> > -------------------------------
> >
> > I encountered a problem in a header file like the following:
> >
> > template <typename DataType>
> > class FMC
> > {
> > public:
> > static DataType Epsilon;
> > private:
> > FMC() {}
> >
> > };
> >
> > template <typename DataType>
> > DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);
>
>
> This is the definition of Epsilon, a static data member of the class
> template FMC. Placing this definition in a header file is likely to
> prove problematic and for the reasons described. Essentially every
> source file that instantiates Epsilon will also define it - leading to
> a multiply-defined symbol error at link time.

As other people have pointed out, this one has to be put in the header
file, and it is correct and will not lead to multiple definitions. For
it is a template, and the compiler/linker will be able to eliminate
multiple instantiations occurring in different translation units.

> > template <>
> > double FMC<double>::Epsilon = static_cast<double>(0.0000000001);
>
>
> This statement is an explicit specialization for Epsilon when FMC is
> instantiated with the type double. Note that the presence of an
> initializer for Epsilon makes this statement a definition - and not a
> declaration - of the explicit specialization. Once again, placing a
> definition in a header file is bound to to lead a multiply-defined
> symbol error if more than one file references FMC<double>::Epsilon.

This one is different, since it is a full specialization. And the rule
is different (see below).

The difference between MSVC 8 and GCC is as follows.

- MSVC 8 will accept such sequence in different translation units:

template <typename DataType>
DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);

template <>


double FMC<double>::Epsilon = static_cast<double>(0.0000000001);

but not this specific sequence (in one translation unit):

template <typename DataType>
DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);

template <>
double FMC<double>::Epsilon; // declaration for specialization

template <>
double FMC<double>::Epsilon = static_cast<double>(0.0000000001);

- GCC, on the contrary, accept only the latter sequence, but not the
former sequence in different translation units.

According the information provided by Maxim Yegorushkin (thanks,
Maxim), C++98 3.2/5 clearly specifies the exceptions to the one
definition rule:

- There can be more than one definition of a class type, enumeration
type, inline function with external linkage, class template, non-static
function template, static data member of a class template, member
function template, or template specialization for which some template
parameters are not specified in a program provided that each definition


appears in a different translation unit, and provided the definitions
satisfy the following requirements...

So GCC is (again!) correct regarding standard conformance.

Thanks to all that have commented (esp. Maxim).

Best regards,

Yongwei

kanze

unread,
May 9, 2006, 4:05:08 PM5/9/06
to

> > -------------------------------

Exactly. On the other hand, the explicit specialization must be
declared in the header in order to prevent an implicit
specialization. How do you declare the explicit specialization
without defining the variable?

The only thing I could come up with is:

template<>
extern double FMC< double >::Epsilon = ...

I'm not 100% sure that extern is legal here, although I cannot
find anything which forbids it. And I'm almost sure that I've
encountered a compiler which refuses it.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

kanze

unread,
May 9, 2006, 4:04:00 PM5/9/06
to
Greg Herlihy wrote:
> Wu Yongwei wrote:
> > I posted the following message days ago to comp.std.c++, and
> > got an helpful answer from Alberto Ganesh Barbati. However,
> > I would like to hear more comments from you gurus here, esp.
> > whether the behaviour of MSVC 8 is standard conforming, best
> > with quotations from the Standard.

> > -------------------------------

> > I encountered a problem in a header file like the following:

> > template <typename DataType>
> > class FMC
> > {
> > public:
> > static DataType Epsilon;
> > private:
> > FMC() {}
> >
> > };

> > template <typename DataType>
> > DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);

> This is the definition of Epsilon, a static data member of the
> class template FMC. Placing this definition in a header file
> is likely to prove problematic and for the reasons described.

Why? It's not problematic at all, and it didn't cause him any
problems. The standard says it has to work (§3.2/5), and I
don't know of a modern compiler where it doesn't work.

> Essentially every source file that instantiates Epsilon will
> also define it - leading to a multiply-defined symbol error at
> link time.

It's true that every source file which instantiates Epsilon will
also define it. That's the implementation's problem, however,
and not yours ; the same thing holds for the constructor, and
presumable, the implementation will use the same mechanisms here
as it does for member functions.

> > template <>
> > double FMC<double>::Epsilon = static_cast<double>(0.0000000001);

> This statement is an explicit specialization for Epsilon when
> FMC is instantiated with the type double. Note that the
> presence of an initializer for Epsilon makes this statement a
> definition - and not a declaration - of the explicit
> specialization. Once again, placing a definition in a header
> file is bound to to lead a multiply-defined symbol error if
> more than one file references FMC<double>::Epsilon.

In this case, there is a problem, because the definition is NOT
a definition of a "static data member of a class template"
(which is covered in §3.2/5), and so may only be defined once.

The problem is that it isn't clear from the standard (to me, at
least) what the correct solution is.

> > When multiple .cpp files include this header file, GCC 3.4.4
> > (or some earlier version) will complain:

> > ...: multiple definition of `FMC<double>::Epsilon'
> > ...

> > To make GCC work, I have to reorganize the header file as follows:

> > - In header file

> > template <typename DataType>
> > class FMC
> > {
> > public:
> > static DataType Epsilon;
> > private:
> > FMC() {}
> > };

> > template <typename DataType>
> > DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);

> Well, this definition staying in the header file can mean only
> one thing: and that is that we probably have not seen the last
> of the multiply-defined symbol error.

Only if you have a broken compiler. Unless the template has
been exported, this definition *MUST* be present in any
translation unit which uses the object. (If the template has
been exported, this definition should be in the implementation
source file of the template. If the template has been exported,
however, he will probably have problems compiling the code with
VC++ or g++.)

> > template <>
> > double FMC<double>::Epsilon;

> This line in contrast has changed - and changed for the
> better. Removing the initializer has transformed an explicit
> specialization definition into an explicit specialization
> declaration.

Sorry. According to §9.4.2, it's a definition. In order for it
not to be a definition, you must declare it extern. It's not
fully clear, however, that extern is legal here, and some
compilers do reject it.

Note that multiple definitions in this case is undefined
behavior. The compiler can reject it, but it can also work.
Apparently, here, it works if there is no initializer, and
doesn't if there is one.

> And the declaration has the opposite affect of the definition.
> It inhibits the instantiation of the FMC<double>::Epsilon in
> source files that reference it - unless that source file has
> FMC<double>::Epsilon's definition.

Both the declaration and the definition inhibit the implicit
instatiation.

> So moving the definition of the explicit specialization into a
> source file ensures that the program defines the static data
> member only once - no matter how many source files actually
> reference it.

The problem is that the standard doesn't really provide a means
of just declaring a static data member of a class outside of the
class definition. And it doesn't allow explicit instantiation
of a static data member of a template class inside the class
definition. Unless extern is legal on the declaration outside
of the class, there is no real solution, as far as the standard
is concerned.

> > - In another .cpp file

> > #include "fmc.h"

> > template <>
> > double FMC<double>::Epsilon = static_cast<double>(0.0000000001);

> > However, then MSVC 8 will choke and declare that the
> > definition in the .cpp file is a redefinition. It works with
> > the original version.

The original version has undefined behavior, so it's acceptable
that it works; the compiler is not required to signal the error
(although it is allowed to). This version does have an error
requiring an error message. (Technically, if "fmc.h" is
included in more than one translation unit, the program has
undefined behavior, and the compiler is off the hook.
Presumably, however, if g++ accepts this, it will also accept
the program if this translation unit contains main(), and is the
only translation unit in the program. If it does so without a
diagnostic, it is an error in the compiler.)

> > My question is, which way is the standard-conforming way?
> > and which compiler is standard conformant on this issue?

> Before we can judge the compilers, we need to get the program
> into a working state.

In order to get the program into a working state, we have to
know what "a working state" is. In this case, the standard
makes a number of requirements, but it's not 100% clear that
there is a standard conforming solution.

> And the structure of this program as we last left it, has only
> a very limited fix for the Epsilon's multiple definition
> problem. In fact it only works in one particular Epsilon - the
> Epsilon for FMC<double>.

Just the contrary. If he removes the explicit instantiation of
FMC<double>::Epsilon, the program works for all possible
instantiations. Of course, the value of FMC<double>::Epsilon
will be 0.0, which isn't what he wants.

> So as matters stand, if the program tries to instantiate FMC
> with a type other than double, and then references that
> template's Epsilon in more than once source file - than the
> exact same problem would happen again.

Have you actually tried this? Or used templates in an actual
program, for that matter?

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Alberto Ganesh Barbati

unread,
May 10, 2006, 8:44:44 AM5/10/06
to
kanze ha scritto:

>>> template <>
>>> double FMC<double>::Epsilon;
>
>> This line in contrast has changed - and changed for the
>> better. Removing the initializer has transformed an explicit
>> specialization definition into an explicit specialization
>> declaration.
>
> Sorry. According to §9.4.2, it's a definition. In order for it
> not to be a definition, you must declare it extern. It's not
> fully clear, however, that extern is legal here, and some
> compilers do reject it.

Sorry to contradict you, but in this case §14.7.3/15 overrules §9.4.2:

"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."

So it IS a declaration.

Ganesh

Gene Bushuyev

unread,
May 10, 2006, 8:41:01 AM5/10/06
to
"kanze" <ka...@gabi-soft.fr> wrote in message
news:1147167575....@g10g2000cwb.googlegroups.com...
[...]

>> OTOH, full specialization is not a template so that the exempt
>> does not apply here, this is why you get the error when you
>> put the full specialization of the static member in the
>> header.
>
> Exactly. On the other hand, the explicit specialization must be
> declared in the header in order to prevent an implicit
> specialization. How do you declare the explicit specialization
> without defining the variable?

I don't think the standard provides a mechanism to achieve it, which implicitly
means you can't. Nevertheless, there is always a possibility to specialize the
whole class template, rather than one member:

In the header file:

template <>
class FMC<double>
{
public:
static double Epsilon;
private:
FMC() {}
};

in the implementation file:

double FMC<double>::Epsilon = whatever;


--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy

Wu Yongwei

unread,
May 10, 2006, 2:37:19 PM5/10/06
to
kanze wrote:
>>> template <>
>>> double FMC<double>::Epsilon;
>
>> This line in contrast has changed - and changed for the
>> better. Removing the initializer has transformed an explicit
>> specialization definition into an explicit specialization
>> declaration.
>
> Sorry. According to §9.4.2, it's a definition. In order for it
> not to be a definition, you must declare it extern. It's not
> fully clear, however, that extern is legal here, and some
> compilers do reject it.

Hi, James, I caught you once :-). According to §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). ]

So the sequence that GCC accepts

// In header file
template <typename DataType>


DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);

template <>
double FMC<double>::Epsilon; // declaration for specialization

// In one .cpp file


template <>
double FMC<double>::Epsilon = static_cast<double>(0.0000000001);

is correct.

Best regards,

Yongwei

kanze

unread,
May 10, 2006, 4:59:22 PM5/10/06
to
Wu Yongwei wrote:
> Greg Herlihy wrote:

> > Wu Yongwei wrote:
[...]


> > > I encountered a problem in a header file like the following:

> > > template <typename DataType>
> > > class FMC
> > > {
> > > public:
> > > static DataType Epsilon;
> > > private:
> > > FMC() {}
> > > };

> > > template <typename DataType>
> > > DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);

[...]

> > > template <>
> > > double FMC<double>::Epsilon = static_cast<double>(0.0000000001);

[...]


> This one is different, since it is a full specialization. And
> the rule is different (see below).

> The difference between MSVC 8 and GCC is as follows.

> - MSVC 8 will accept such sequence in different translation units:

> template <typename DataType>
> DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);

> template <>
> double FMC<double>::Epsilon = static_cast<double>(0.0000000001);

Which it is allowed to do -- but not required: the repetition of
the second one is a multiple definition, which is undefined
behavior.

> but not this specific sequence (in one translation unit):

> template <typename DataType>
> DataType FMC<DataType>::Epsilon = static_cast<DataType>(0.000001);

> template <>
> double FMC<double>::Epsilon; // declaration for specialization

> template <>
> double FMC<double>::Epsilon = static_cast<double>(0.0000000001);

Which is correct; the standard requires a diagnostic in this
case, because of the double definition.

> - GCC, on the contrary, accept only the latter sequence, but
> not the former sequence in different translation units.

In which case, it is in error, because the standard requires a
diagnostic for double definitions which appear in the same
translation unit.

> According the information provided by Maxim Yegorushkin
> (thanks, Maxim), C++98 3.2/5 clearly specifies the exceptions
> to the one definition rule:

> - There can be more than one definition of a class type, enumeration
> type, inline function with external linkage, class template, non-static
> function template, static data member of a class template, member
> function template, or template specialization for which some template
> parameters are not specified in a program provided that each definition
> appears in a different translation unit, and provided the definitions
> satisfy the following requirements...

> So GCC is (again!) correct regarding standard conformance.

I don't see it. Where does it say that there can be more than
one definitioin of a complete specification? It allows only
mutliple definitions of a partial specialization: "template


specialization for which some template parameters are not

specified". (Note that your specialization is NOT a "definition
of [... a] static data member of a class template", but a
specialization of said data member.)

The correct solution requires that the header only contain a
declaration, not a definition. And the only way for a data
declaration at namespace scope to be a declaration is for the
declaration to contain the keyword "extern". Which g++ accepts,
but not Sun CC nor VC++. Since the standard also says
(§7.1.1/5) "The extern specifier cannot be used in the
declaration of class members or function parameters", there is
certainly an argument for their refusing it.

The current situation is that 1) there is no way to portably
declare an explicit specialization of a static data member of a
template class so that it can be used in more than one
translation unit, and 2) it's far from clear that the standard
even allows it. Of the two ways you describe, one has undefined
behavior, because of illegal multiple definitions, and the other
requires a diagnostic, because of multiple definitions in the
same translation unit. Adding extern to the definition without
an initializer avoids those problems, but it is far from clear
that it is legal.

I rather suspect that a defect report is in order.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

kanze

unread,
May 10, 2006, 5:00:06 PM5/10/06
to
Alberto Ganesh Barbati wrote:
> VSR ha scritto:
> > I am sorry, not had my coffee yet this morning. but at first
> > look, I do not see any problem with the compiler.

> >> However, then MSVC 8 will choke and declare that the
> >> definition in the .cpp file is a redefinition. It works
> >> with the original version.

> > well you are redefining the variable and *all* C++ compilers
> > should crib about that. Its not about standards, it is about
> > syntax.

> As you are not quoting the source, it's not clear what
> variable are you talking about. If you are talking about
> double FMC<double>::Epsilon in the *second* example, then your
> remark is wrong, because the line:

> template <>
> double FMC<double>::Epsilon;

> is a declaration, not a definition 14.7.3/15.

Thanks. That's the part I'd missed. (They even mention the
obvious weakness of this in the note -- it doesn't allow types
which use default initialization.)

Regretfully, most compilers don't seem to implement it: recent
versions of g++ are OK, but both Sun CC nor VC++ complain about
multiple definitions.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Alberto Ganesh Barbati

unread,
May 11, 2006, 8:32:54 AM5/11/06
to
Gene Bushuyev ha scritto:

> "kanze" <ka...@gabi-soft.fr> wrote in message
> news:1147167575....@g10g2000cwb.googlegroups.com...
> [...]
>>> OTOH, full specialization is not a template so that the exempt
>>> does not apply here, this is why you get the error when you
>>> put the full specialization of the static member in the
>>> header.
>> Exactly. On the other hand, the explicit specialization must be
>> declared in the header in order to prevent an implicit
>> specialization. How do you declare the explicit specialization
>> without defining the variable?
>
> I don't think the standard provides a mechanism to achieve it, which implicitly
> means you can't. Nevertheless, there is always a possibility to specialize the
> whole class template, rather than one member:

As I said in another post, the following:

template <>
double FMC<double>::Epsilon;

is precisely the declaration you both seek. See 14.7.3/15 for reference.

Ganesh

kanze

unread,
May 11, 2006, 6:58:14 PM5/11/06
to
Alberto Ganesh Barbati wrote:
> kanze ha scritto:
> >>> template <>
> >>> double FMC<double>::Epsilon;

> >> This line in contrast has changed - and changed for the
> >> better. Removing the initializer has transformed an explicit
> >> specialization definition into an explicit specialization
> >> declaration.

> > Sorry. According to §9.4.2, it's a definition. In order for it
> > not to be a definition, you must declare it extern. It's not
> > fully clear, however, that extern is legal here, and some
> > compilers do reject it.

> Sorry to contradict you, but in this case §14.7.3/15 overrules §9.4.2:

> "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."

> So it IS a declaration.

So I see. There was a fairly long discussion concerning this in
the German speaking newsgroup recently, and no one caught my
error there.

I'll admit that this possibility hadn't occurred to me, because
it seemed obvious that it had an important restriction: how do
you definine the specialization for a class which has a default
constructor (and no other). The answer is, apparently, that you
can't. It sounds like a gratuitous restriction, since allowing
extern on the declaration is such an obvious solution, but I
doubt that it's a serious restriction in practice.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Wu Yongwei

unread,
May 13, 2006, 4:31:57 PM5/13/06
to

template <>
MyClassWDflCtor MyTmpl<MyClassWDflCtor>::Obj;

and then

template <>
MyClassWDflCtor MyTmpl<MyClassWDflCtor>::Obj = MyClassWDflCtor();

Don't you think it can work?

However, why would you want it to be specialized while
default-constructed? The above specialization is completely
unnecessary, and I cannot think of a case where it could be useful.

Best regards,

Yongwei

James Kanze

unread,
May 14, 2006, 1:53:57 PM5/14/06
to
Wu Yongwei wrote:

[...]


> template <>
> MyClassWDflCtor MyTmpl<MyClassWDflCtor>::Obj;

> and then

> template <>
> MyClassWDflCtor MyTmpl<MyClassWDflCtor>::Obj = MyClassWDflCtor();

> Don't you think it can work?

Not if MyClassWDflCtor doesn't support copy construction.

> However, why would you want it to be specialized while
> default-constructed? The above specialization is completely
> unnecessary, and I cannot think of a case where it could be
> useful.

I don't know. I've not encountered the case. It just seems an
arbitrary and unnecessary restriction.

--
James Kanze kanze...@neuf.fr


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

Wu Yongwei

unread,
May 15, 2006, 8:06:58 AM5/15/06
to
James Kanze wrote:

> Wu Yongwei wrote:
> > However, why would you want it to be specialized while
> > default-constructed? The above specialization is completely
> > unnecessary, and I cannot think of a case where it could be
> > useful.
>
> I don't know. I've not encountered the case. It just seems an
> arbitrary and unnecessary restriction.

I suppose you meant something like this:

-------- begin code --------
class MyObj {
public:
MyObj() : val(1) {}
MyObj(int n) : val(n) {}
private:
int val;
};

template <typename Obj>
class MyTmpl {
public:
static Obj myObj;
};

template <typename Obj>
Obj MyTmpl<Obj>::myObj(0);

template <>
MyObj MyTmpl<MyObj>::myObj; // How can I define the data member
since

template <>
MyObj MyTmpl<MyObj>::myObj(); // this line cannot compile?
-------- end code --------

As can be clearly seen, the static data member has to have a
non-default constructor (unlike the assumption you had) to make the
specialization behave differently. In the above case, I can easily use
`myObj(1)' instead of `myObj()' to make it work.--If in any case the
default contructor could do something the non-default constructor
cannot do, I would consider it a design flaw.

So I believe the `restriction' is nearly nothing in real worlds.

Best regards,

Yongwei

0 new messages