Linker error with static variable

I'm getting a curious linker error when passing a static member variable to std::min.

struct test
{      
      const static int val = 555;
};

int main()
{
      int x = std::min(344, test::val);
}

This causes a linker error with an undefined reference to test::val.  It's easy enough to work around - I can simply use a temporary like this:

      int x = std::min(344, int(test::val));

But why do I need to do this?  Is it something to do with std::min being a templated function?
chsalviaAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Infinity08Commented:
struct test
{      
      const static int val;
};

const int test::val = 555;

int main()
{
      int x = std::min(344, test::val);
}
0
Infinity08Commented:
or alternatively :

struct test
{      
      const static int val = 555;
};

const int test::val;

int main()
{
     int x = std::min(344, test::val);
}


But the point is that you need to define the static member outside of the class/struct.
0
chsalviaAuthor Commented:
I thought it wasn't necessary to declare static member variables outside of the class if the type is a POD.  

Also, I'm able to use the variable outside the class - the linker error only occurs when I pass it to std::min.  But why does passing the variable to std::min trigger the linker error?
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

evilrixSenior Software Engineer (Avast)Commented:
This works fine on VC++2005 --> What platform/compiler are you using? It probably doesn't support in-place assignment (it was a late edition to the standard)


>> I thought it wasn't necessary to declare static member variables outside of the class if the type is a POD
Normally you don't -- unless it's a non const, non-pod non-intrinsic, but it might be an older compiler that doesn't support this part of the standard.
#include <algorithm>
 
struct test
{      
      const static int val = 555;
};
 
int main()
{
      int x = std::min(344, test::val);
}

Open in new window

0
ravenplCommented:
If You declare const static simple type, and then initialize along with in declaration
the variable is not created in fact, therefore You can't take it's pointer or reference - which std::min wants.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Infinity08Commented:
>> I thought it wasn't necessary to declare static member variables outside of the class if the type is a POD.  

A static member is declared inside the struct, but defined outside the struct :

        struct test
        {      
              const static int val;        // <--- declaration
        };
       
        const int test::val = 555;    // <--- definition

The reason it needs to be defined at file scope is because a static member variable are not part of the objects ... they are a separate entity with their own storage.


In C++, a struct is just a class with different access defaults (private vs. public). So, whether you use a struct or a class doesn't make a difference.


>> Also, I'm able to use the variable outside the class - the linker error only occurs when I pass it to std::min.  But why does passing the variable to std::min trigger the linker error?

That's probably due to the interpretation of this paragraph in the C++ standard :

        If a static data member is of const integral or const enumeration type, its declaration in the class
        definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that
        case, the member can appear in integral constant expressions. The member shall still be defined in a namespace
        scope if it is used in the program and the namespace scope definition shall not contain an initializer.
0
evilrixSenior Software Engineer (Avast)Commented:
>> If You declare const static simple type, and then initialize along with in declaration
Eh? You mean like http:#20736822 ?

Check out this tutorial on class member initialization.
http://www.devx.com/getHelpOn/10MinuteSolution/17298/1954
0
Infinity08Commented:
Clicked submit too early - here's the rest of the post :

Or more specifically, this part : "In that case, the member can appear in integral constant expressions."
When you use the static const int like this :

         std::cout << test::val;

there's no problem, since you're accessing it as a const integral expression. However, when using it with min, you try to take the reference of a const integral expression ... That's not possible ;)
0
Infinity08Commented:
>> This works fine on VC++2005

That means your compiler is "broken" ;) It doesn't follow the C++ standard ;)
0
evilrixSenior Software Engineer (Avast)Commented:
As usual it seems different compilers interpret that differently due to the ambiguity of the wording. Don't you just love the standard :)
0
evilrixSenior Software Engineer (Avast)Commented:
>> It [VC2005] doesn't follow the C++ standard
No way, I don't believe that for 1 moment ;-)
0
Infinity08Commented:
>> >> It [VC2005] doesn't follow the C++ standard
>> No way, I don't believe that for 1 moment ;-)

You have to admit it does something quite fishy there ... take a reference of a const integral EXPRESSION hehe
0
evilrixSenior Software Engineer (Avast)Commented:
The wording is slightly ambiguous IMO. I have to be honest I've never had a problem but then I don't often need to define class level constants.
0
Infinity08Commented:
Well, the only way VC2005 would be able to compile that code is if it interpreted the declaration as a definition :

        struct test
        {      
              const static int val = 555;    // <--- VC2005 sees this as a definition instead of a declaration
        };

which the standard clearly contradicts :

        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 members class definition.


Or possibly VC2005 did some early optimization, which is equally bad ...
0
evilrixSenior Software Engineer (Avast)Commented:
I've just re-read that section in the standards doc and on reflection I do agree, it shouldn't compile.
9.4.2-4 "If a static data member is of const integral or const enumeration type, its declaration in the class
definition can specify a constant-initializer which shall be an integral constant expression (5.19).  In that
case, the member can appear in integral constant expressions.  The member shall still be defined in a name-
space scope if it is used in the program and the namespace scope definition shall not contain an initializer."

Open in new window

0
Infinity08Commented:
Thinking about it a bit more, I do agree that it is ambiguous though, because you can do this :

        const int &ref = 5;

just not this :

        struct test {      
              static const int val = 5;
        };

        const int &ref = test::val;

mmm ... long live the standard lol.
0
evilrixSenior Software Engineer (Avast)Commented:
>> mmm ... long live the standard lol.
Yes, we've spoken about this before -- a lot of it is subjective depending upon what phase the moon is currently in :)

You know this is all peetm's fault -- he's even admitted as much :)

BTW: Do you have the ANSI ISO number for the (various) C standard(s)? I don't have a copy of that (I have both 98 and 03 versions of C++) and I could do with acquiring a copy (hopefully online via Google).
0
Infinity08Commented:
The C standard : ISO/IEC 9899
C99 for example : ISO/IEC 9899:1999
0
evilrixSenior Software Engineer (Avast)Commented:
Ta very muchly.
0
evilrixSenior Software Engineer (Avast)Commented:
There are some interesting docs here: http://www.open-std.org/jtc1/sc22/wg14/www/docs/
0
Infinity08Commented:
The most interesting in that list is the n1124.pdf ... It differs very little from the "real" C99 doc.
0
evilrixSenior Software Engineer (Avast)Commented:
n1255.pdf interested me: CERT C Programming Language Secure Coding Standard
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.