Bug 20547 - undefined reference to "static const" fields of classes
Summary: undefined reference to "static const" fields of classes
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.4.4
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 29219 (view as bug list)
Depends on:
Blocks:
 
Reported: 2005-03-19 06:59 UTC by ­J©¨°¶
Modified: 2006-09-25 21:11 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
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 ­J©¨°¶ 2005-03-19 06:59:21 UTC
The sample codes¡G
==========================================
#include <iostream>
#include <vector>

struct T
{
  static char const a = 3;
};

std::vector<char> ddd;

int
main()
{
  ddd.push_back(T::a); /* this line of codes trigger the errors */

  std::cerr << ddd.front() << std::endl;

  return 0;
}
========================================

gcc-3.0.x 3.2.x 3.3.x 3.4.x compile the above program will produce errors like this:
=======================================
/tmp/ccPOPHZ6.o(.text+0x124): In function `main':
: undefined reference to `T::a'
collect2: ld returned 1 exit status
=======================================

However, if I use gcc-2.95, then there will be no errors.

If I modify the codes from:

...
ddd.push_back(T::a);
...

to

...
ddd.push_back(static_cast<char>(T::a));
...

then gcc-3.0.x 3.2.x 3.3.x 3.4.x will be fine.

Is this a bug in gcc 3.x?
Comment 1 Andrew Pinski 2005-03-19 13:45:42 UTC
No you need to add the following to your code:
const char T::a;

Since you don't supply the memory location otherwise (which is required by the standard).
Comment 2 ­J©¨°¶ 2005-03-19 13:53:21 UTC
But according the standard, 'const static' data members of an intergral type can
now be initialized _inside_ their class. In this case, the initialization is
_also_ a definition, so _no_ further definitions are reuquired outside the class
body.
Comment 3 ­J©¨°¶ 2005-03-19 14:01:03 UTC
#include <vector>

struct T
{
  static char const a = 3;
};

void
fff(char a)
{
}

std::vector<char> b;

int
main()
{
  fff(T::a); /* this line of codes is fine. */

  b.push_back(T::a); /* however, this line of codes is an error. */

  return 0;
}
Comment 4 Andrew Pinski 2005-03-19 14:03:41 UTC
(In reply to comment #2)
> But according the standard, 'const static' data members of an intergral type can
> now be initialized _inside_ their class. In this case, the initialization is
> _also_ a definition, so _no_ further definitions are reuquired outside the class
> body.

No it is not a definition, a definition (or is it the other way around).  Still this is invalid.  Yes the compiler 
is allowed to "optimize" the constant which is why it worked in 2.95.3 (well because the defintion of 
push_back was wrong).

Oh, one more thing, the vector code is equivalent to (so you take the address):
struct T
{
  static char const a = 3;
};
void
fff(const char &a){ }
int
main()
{
  fff(T::a);

  return 0;
}
Comment 5 ­J©¨°¶ 2005-03-19 14:15:58 UTC
I understand what you mean.
But why the following codes works:

#include <iostream>
#include <vector>

struct T
{
  static char const a = 3;
};

std::vector<char> ddd;

int
main()
{
  ddd.push_back(static_cast<char>(T::a)); // <========= here

  std::cerr << ddd.front() << std::endl;

  return 0;
}

and if I pass an constant to a function which takes its address,
then why the folloing codes doesn't produce errors?

void
fff(char const &a)
{
}

int
main()
{
  fff(4);

  return 0;
}
Comment 6 Andrew Pinski 2005-03-19 14:34:16 UTC
(In reply to comment #5)
> I understand what you mean.
> But why the following codes works:
> 
> #include <iostream>
> #include <vector>
> 
> struct T
> {
>   static char const a = 3;
> };
> 
> std::vector<char> ddd;
> 
> int
> main()
> {
>   ddd.push_back(static_cast<char>(T::a)); // <========= here
> 
>   std::cerr << ddd.front() << std::endl;
> 
>   return 0;
> }
> 
> and if I pass an constant to a function which takes its address,
Because you changed an lvalue to a rvalue.

> then why the folloing codes doesn't produce errors?

Because constants are rvalues so there is going to be a temporary variable made for you.
Comment 7 ­J©¨°¶ 2005-03-19 18:25:54 UTC
I see.
But why compiler doesn't also make a temporary variable for the constant defined
in a class scope?
Such as following codes:

struct T
{
  static int const a = 3;
};

void
fff(int const &a)
{
}

int
main()
{
  fff(T::a); /* compiler will not make a temporary variable for it. */
  fff(4); /* compiler will make a temporary variable for it. */

  return 0;
}
Comment 8 Andrew Pinski 2005-03-19 18:35:51 UTC
Bacause T::A is a lvalue.
Comment 9 ­J©¨°¶ 2005-03-20 07:59:16 UTC
so the "... = 3;" initialization statement below is a definition or a declaration?
According to the C++ standard, its a definition.
Should the compiler allocate a memory space for it?

struct T
{
  static char const a = 3;
};

And...
If I need to allocate memory spaces for it manually, why the standard explicitly
specify this kind of coding style?
========================
struct T
{
  static char const a = 3; /* standard explicity specify that the initialization
& definition can be put here. */
};

char const T::a; /* If I need this line of codes, then the initialization above
should be a declaration, not a definition. But a declaration can be initialized? */
========================
struct T
{
  static char const a;
};

char const T::a = 3;
========================
Comment 10 Kriang Lerdsuwanakij 2005-03-20 13:55:25 UTC
Here is the relevant section of the standard (TC1, 
section 9.4.2, paragraph 4):

  If a 'static' data member is of 'const' integral or 'const' enumeral 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'.
Comment 11 Andrew Pinski 2006-09-25 21:11:18 UTC
*** Bug 29219 has been marked as a duplicate of this bug. ***