Alex Rivera | Logout

C++ integral constants + choice operator = problem!

Asked 2010-11-17T21:41:14.407
9

I have recently discovered an annoying problem in some large program i am developing; i would like to understand how to fix it in a best way. I cut the code down to the following minimal example.

#include <iostream>
using std::cin;
using std::cout;

class MagicNumbers
{
public:
  static const int BIG = 100;
  static const int SMALL = 10;
};

int main()
{
  int choice;
  cout << "How much stuff do you want?\n";
  cin >> choice;
  int stuff = (choice < 20) ? MagicNumbers::SMALL : MagicNumbers::BIG; // PROBLEM!
  cout << "You got " << stuff << "\n";
  return 0;
}

I get link errors in gcc 4.1.2 when compiling with -O0 or -O1 but everything is OK when compiling with -O2 or -O3. It links well using MS Visual Studio 2005 regardless of optimization options.

test.cpp:(.text+0xab): undefined reference to `MagicNumbers::SMALL'

test.cpp:(.text+0xb3): undefined reference to `MagicNumbers::BIG'

I looked at the intermediate assembly code, and yes, the non-optimized code regarded SMALL and BIG as external int variables, while the optimized one used the actual numbers. Each of the following changes fixes the problem:

  • Use enum instead of int for constants: enum {SMALL = 10}

  • Cast the constant (any one) at each usage: (int)MagicNumbers::SMALL or (int)MagicNumbers::BIG or even MagicNumbers::SMALL + 0

  • Use a macro: #define SMALL 10

  • Not use the choice operator: if (choice < 20) stuff = MagicNumbers::SMALL; else stuff = MagicNumbers::BIG;

I like the first option best (however, it's not ideal because we actually use uint32_t instead of int for these constants, and enum is synonymous with int). But what i really want to ask is: whose bug is it?

Am i the one to blame for no

Edit
Report

1 Answer

3

Heh, according to the C++ standard, 9.4.2 (class.static.data):

If a static data member is of const literal type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note ] 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.

So the declaration is correct, but you still need to have a definition somewhere. I always thought you could skill the definition, but I suppose that isn't standard conforming.

answered 2010-11-17T22:01:48.307

Your Answer