C++ integral constants + choice operator = problem!

天涯浪子 提交于 2019-11-30 13:01:22

In spite of the conventional advice, I have found that static const int ... invariably gives me more headaches than good old enum { BIG = 100, SMALL = 10 };. And with C++11 providing strongly-typed enums, I now have even less cause to use static const int ....

This is a known issue. The Standard is to blame or you for not providing a definition of the statics. Depending on your point of view :)

Static data members don't work like that in C++:

Static data members are not part of objects of a given class type; they are separate objects. As a result, the declaration of a static data member is not considered a definition. The data member is declared in class scope, but definition is performed at file scope. These static members have external linkage.

You're only declaring those constants, even though you're initializing them. You still have to define them at namespace scope:

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

const int MagicNumbers::BIG;
const int MagicNumbers::SMALL;

That will get rid of the link errors.

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.

I'm new to C++, but I think that your class declaration only declares that those static members exist, you still need to define them somewhere:

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

const int MagicNumbers::BIG = 100;
const int MagicNumbers::SMALL = 10;

The higher optimisation levels probably include a level of static analysis thorough enough to determine that BIG and SMALL can be exchanged with their actual values and not to give them any actual storage (the semantics will be the same), so defining these variables in this circumstance would be redundant, hence it links OK.

I'd be hard pressed to assert that it's anyone's bug.

Static const integrals given values at point of declaration are not variables, they're constant expressions. For there to be a variable you still need to define it.

The rules wrt the ternary operator are pretty absurdly complex, probably necessarily so, and actually doesn't really say anything about constant expressions, only rvalues; obviously the compiler thinks they should be variables unless optimization is cranked way up. I think it's free to interpret the expression either way (as a constant expression or as variable).

You still need to allocate space for them somewhere:

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

Why are your magic numbers in a class?

namespace MagicNumbers {
    const int BIG = 100;
    const int SMALL = 10;
}

Problem solved without needing to worry about flaws in the C++ standard.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!