none
In-class static const member initialization and LNK2005 RRS feed

  • Question

  • Hello everybody,

    Recently I ran into following issue with MSVC linker:

    C++ Standard, Sec. 9.4.2 paragraph 4 says:
    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.

    So I created following project:

    Test.h:

    #ifndef TEST_H
    #define TEST_H
    
    class Test
    {
    public:
        static const int s = 13;
    };
    
    #endif
    



    Test.cpp:
    #include "Test.h"






    const
    int Test::s;

    another.cpp:
    #include "Test.h"
    
    int function(const int& a) {
        return Test::s + a;
    }
    
    

    main.cpp:
    #include <iostream> 
    #include "Test.h"
    
    using namespace std; 
    
    int function (const int&);
    
    int
    main() { cout << Test::s << ' ' << function(Test::s) << '\n'; }

    When building this project, all is compiled succesfully, but linker is unhappy with:

    Linking...
    another.obj : error LNK2005: "public: static int const Test::s" (?s@Test@@2HB) already defined in Test.obj
    main.obj : error LNK2005: "public: static int const Test::s" (?s@Test@@2HB) already defined in Test.obj
    e:\path\prog.exe : fatal error LNK1169: one or more multiply defined symbols found

    Except for the code to be completely pointless - it is just for illustration purposes - is there anything wrong with it in terms of C++ language? Problem seems to occur only when I have some static const fields with in-class initializer AND namespace-scope definition. function takes its parameter by const reference to utilize "used elsewhere in program" words mentioned by Standard, as opposed to just "used in constant epression" - so it requires namespace scope definition of static field. At least I think so. Anyway, even with parameter passed by value, problem seems to persist. Removing namespace-scope definition makes MSVC linker happy, but it makes my program ill-formed when I want this field to be "used in program" in any other way than in constant expression (like, let's say, want to have its address taken). Removing in-class initializer and initializing field in namespace scope also fixes things, and it can be used as a workaround. But my question is: does MSVC linker do not get what Standard says correctly, or I am missing something?

    MSVC version used: Microsoft Visual C++ 2008 Express Edition.
    • Edited by Hobson Wednesday, February 10, 2010 10:11 PM code firmatting
    Wednesday, February 10, 2010 9:28 PM

All replies

  • 'const int Test::s;' in test.cpp is in fact defining (but not initializing) s a second time. Remove this line and everything will be fine.
    • Proposed as answer by «_Superman_» Thursday, February 11, 2010 5:52 AM
    • Unproposed as answer by Hobson Thursday, February 11, 2010 7:34 AM
    Thursday, February 11, 2010 2:20 AM
  • I am sorry if my explanation was not clear enough for you, but I am not native English speaker, so it could be so. Let me rephrase then:

    I do know, that removing this definition makes MSVC linker happy. But please read a paragraph of C++ Standard I quoted above and tell me whether I am wrong believing that this definition is required (by Standard, standard-compliant build systems, and, in general, rest of the C++ world outside MSVC) when I want to use static const field in context other than const integral expression (for example, when I want to have its addres taken). If it is not required, tell me where I misinterpreted paragraph quoted above.

     

    I hope I asked clearer this time.

    Cheers

    Thursday, February 11, 2010 7:33 AM