0

I was hoping C++11 would allow a clean way of defining constants that are scoped inside a class (to prevent pollution of or collisions in the global namespace). My attempt led me to this technique:

struct Foo {
    static constexpr const char* BAZ = "BAZ";
}

However, this will sometimes result in linker failures about undefined references to BAR. Indeed, this is not a definition of BAR, but a definition of its default value. Right?

What confuses me is that this sometimes works. I'll take a guess as to why... constexpr tells the compiler that it can treat this as a compile time constant, but it doesn't have to. So in some cases where BAR is used, the compiler may treat it as a compile time constant (and the translation unit would have a pointer effectively to the .rodata section (or .text or whatever the case may be) of the binary), and in others it may reference the variable BAR (and expect it to be resolved by the linker.) Is this logic sound?

So my question: Is there a way to make this technique work, perhaps by coercing the compiler to prefer treating this as a compile time constant in all cases?

Note that a proper definition of BAR (e.g. Foo:BAR; in source file) is not a viable solution -- keeping up with two lines of code for a constant is cumbersome.

notlesh
  • 625
  • 7
  • 17
  • 2
    Whether you need an out of class definition depends if it [odr-used or not](http://stackoverflow.com/q/8016780/1708801) – Shafik Yaghmour Apr 10 '15 at 16:46
  • Why don't you use `namespace` instead of `struct`? – Ivan Aksamentov - Drop Apr 10 '15 at 16:46
  • see also http://stackoverflow.com/q/272900/103167 – Ben Voigt Apr 10 '15 at 16:48
  • @BenVoigt This isn't a duplicate, at least of that question. I'm asking why this sometimes works and sometimes doesn't, and whether I have control over that. – notlesh Apr 10 '15 at 16:50
  • @stephelton: Did you read the answers to that question, specifically about the interplay between constant expressions and const references? In fact, your exact question "So in some cases where BAR is used, the compiler may treat it as a compile time constant (and the translation unit would result in "1"), and in others it may reference the variable BAR (and expect it to be resolved by the linker.) Is this logic sound?" is answered there. – Ben Voigt Apr 10 '15 at 16:50
  • @ShafikYaghmour there are zero definitions in this case, right? And that's the idea. I want the compiler to treat this as a compile time constant. – notlesh Apr 10 '15 at 16:51
  • @Drop because the need for the constant arises while implementing part of a class -- the proper place for that constant is [arguably] within that class. – notlesh Apr 10 '15 at 16:52
  • The “why doesn't this work” has already been addressed. I like to use the following workaround, which, unfortunately, cannot be posted as an answer any more: `struct Foo { static constexpr int BAR() { return 1; } };` Here, the linker is *required* to do the magic it takes to get your references right. – 5gon12eder Apr 10 '15 at 16:52
  • @Drop: That would replace a "no definitions" error with a "multiple definitions" error. – Ben Voigt Apr 10 '15 at 16:53
  • You don't show enough code but if you take the address or a reference then it is odr-used. – Shafik Yaghmour Apr 10 '15 at 16:53
  • I modified the question to use the more interesting case of a const char* pointer. The previous case of an int was a little more cut and dried -- clearly taking the address of an undefined variable is not going to work. You could do the same with a const char*, but that case is more easily avoided. – notlesh Apr 10 '15 at 17:06

0 Answers0