tags:

views:

243

answers:

3

Consider the following snippet:

struct Foo
{
    static const T value = 123; //Where T is some POD-type
};

const T Foo::value; //Is this required?

In this case, does the standard require us to explicitly declare value in a translation unit? It seems I have conflicting information; boost and things like numeric_limits from the STL seem to do this sort of thing just like in my snippet.

OTOH, I remember reading somewhere (albeit a long long time ago) that you're still required to provide a declaration in a translation unit.

If this is the case, what about template specialization? Will each specialization require a declaration?

I'd appreciate your comments as to what the "right way" is.

+3  A: 

You have to provide a definition in a translation unit too, in case you use the value variable. That means, if for example you read its value.

The important thing is that the compiler is not required to give a warning or error if you violate that rule. The Standard says "no diagnostic required" for a violation.

In the next C++ Standard version, the rule changed. A variable is not used when it is used as a constant expression. Simply reading value above where the variable is initialized directly in the class means that still no definition is required then.

See the definition of use in section 3.2 One Definition Rule of the Standard and requirement for a definition for static data-members in 9.4.2, paragraph 4 and 5 (in the C++98 Standard. Appears in paragraph 3 and 4 in the n2800 draft of the next Standard).

Correction: The rule already changed for c++03: If the variable appears where a integral constant expression is required, no definition is needed (quoting from an unofficial revisions list for the 2003 update), see resolution for this language defect report:

An expression is potentially evaluated unless it appears where an integral constant expression is required (see 5.19), is the operand of the sizeof operator (5.3.3), or is the operand of the typeid operator and the expression does not designate an lvalue of polymorphic class type (5.2.8)...

Note that even then, many uses are in cases where an integral constant is not required. Cases where one is, is in array dimensions or in template metaprogramming. So strictly speaking (see this report), only the c++1x solution provides really guarantee that in obvious cases also like "s == string::npos" where an integral constant is not required the definition of the static member is not needed, because the next Standard has a different, better wording of 3.2. This is however quite theoretical stuff, since most (all?) compiler don't moan anyway. Thanks for the guy in the comment section for telling me.

Johannes Schaub - litb
So, just to clarify, what numeric_limits does, for instance, is technically "illegal"?Perhaps I misunderstood...
yeah. upon a violation, the standard places no requirements anymore on the implementation. the compiler may refuse it, or may accept it. it's up to it. but how do you know your compiler provides no definition? note you have to look into a implementation file. the .h file won't have the definition.
Johannes Schaub - litb
Well, I tested by simply including the standard limits header, and generated pre-processed output. MSVC's (9, if that matters), implementation does not define any of the static constant members outside of any numeric_limits' specializations. Even Comeau's compiler eats this snippet without problems.
yeah. indeed the definition is placed into the library, exact one definition for each. otherwise, if you would include <limits> multiple times, you would get multiple definitions which is a direct violation of the one definition rule.
Johannes Schaub - litb
If T is something from the int family, then you don't have to provide a definition as long as you don't try to take the address of that member or use it in some way that requires storage.
Brian Neal
you are right the rule changed already for c++03. i should have looked in the revisions list because i only have the c++98 document available. thanks for telling me.
Johannes Schaub - litb
dammit. now i have to change those SO comments and answers where i told them a definition is required. too bad :(
Johannes Schaub - litb
No, I think this pre-dates C++03. My copy of Stroustrup is from 2000, and this is explained in section 10.4.6.2. It may be possible that the standard is only now catching up. But I've done this hundreds of times using many different compilers and never needed a definition.
Brian Neal
yeah i think no compiler will moan anyway because it's useful and no diagnostic was required. but my copy of c++98 says it's invalid. maybe stroustrup was refering to common behavior of the compilers in his book. I dunno. if you found where c++98 says it's valid, please show me, i'm interested
Johannes Schaub - litb
Brian, i've found it: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48 . well they found a solution '99 (after they released c++98). so stroustrup probably considered that change when he wrote that book thinking of readers reading it 3 years later :)
Johannes Schaub - litb
Cool. I'm guessing it was agreed-to behavior, and was already widely implemented, but wasn't adequately captured in the '98 spec.
Brian Neal
yeah something like that i think. so one could probably trust it works anyway by high chance :p
Johannes Schaub - litb
A: 

To add on to what litb said, from my copy of n2798:

9.4.2

[...]

2 The declaration of a static data member in its class definition is not a definition and
may be of an incomplete type other than cv-qualified void. The definition for a static
data member shall appear in a namespace scope enclosing the member’s class definition. In the definition at namespace scope, the name of the static data member shall be qualified by its class name using the :: operator.

dirkgently
Helpful, thanks!
A: 

You don't have to provide a definition for static integral constant members if you don't use them in some way that requires them to be stored in memory somewhere (e.g. take the address of such a member). See Stroustrup's The C++ Programming Language, section 10.4.6.2.

Edit: Oops, I just re-read the question, and the question was for some type T. In general you would need to provide a definition, I agree. But if you used something from the int family, you wouldn't necessarily have to (with the caveat above).

Brian Neal