26

I'm wondering why the integer ii is initiallized at compile time, but not the float ff here:

int main() {
  const int i = 1;
  constexpr int ii = i;

  const float f = 1.0;
  constexpr float ff = f;
 }

This is what happens when I try to compile:

> g++ -std=c++11 test.cc
test.cc: In function ‘int main()’:
test.cc:6:24: error: the value of ‘f’ is not usable in a constant expression
   constexpr float ff = f;
                        ^
test.cc:5:15: note: ‘f’ was not declared ‘constexpr’
   const float f = 1.0;
5gon12eder
  • 24,280
  • 5
  • 45
  • 92
Don Slowik
  • 965
  • 10
  • 18
  • 2
    constant integers are somewhat special in C++ – bolov Jan 07 '16 at 21:05
  • My money's on incomplete or flawed compiler implementation of the standard. Haven't checked, but that's what my gut tells me... Have you tried with other compilers (e.g. clang++)? – Parthian Shot Jan 07 '16 at 21:05
  • @Parthean g++ -std=gnu++11 test.cc produced exactly the same results, and clang gives the same in it's own 'language'. – Don Slowik Jan 07 '16 at 21:13
  • 3
    Pretty much historical reasons. CWG recently [decided against](http://wg21.link/CWG1826) changing the rules here. – T.C. Jan 07 '16 at 21:15
  • 1
    Possible duplicate: [Assign a const to a constexpr variable](http://stackoverflow.com/questions/31366213/assign-a-const-to-a-constexpr-variable) – NathanOliver Jan 07 '16 at 21:18
  • I believe the relevant standardese can be found in the 9th item of § 5.19 ¶ 2 in N3337 but I'm not sure. – 5gon12eder Jan 07 '16 at 21:18

2 Answers2

21

Constant variables of integral types with constant initializers are integral constant expressions (de facto implicitely constexpr; see expr.const in ISO C++). float is not an integral type and does not meet the requirements for constant expression without the use of constexpr. (A similar case is why int can be but float cannot be a template parameter.)

StenSoft
  • 9,369
  • 25
  • 30
  • This would explain things. Analogous behaviour is confirmed among the other integral types (bool, short - long long). Also, see the link provided in @T.C.s comment above for the discussions as to why things are this way. – Don Slowik Jan 07 '16 at 21:58
  • So Bjarne misspoke in section 10.4.2 when he said "A const initialized with a constant expression can be used in a constant expression." He gives the int case as an example, not the float... – Don Slowik Jan 07 '16 at 22:06
  • The easy fix is to explicitly label the const float f, in the OP as constexpr float f. This is what the standards folks discussed as a possible requirement for ints as well from T.C.'s link. – Don Slowik Jan 07 '16 at 22:10
  • Yeah, I would say that that definition by Bjarne is pretty vague. Even in his example just below it, the impossibility of using `const string` breaks that rule for non-literal types. – StenSoft Jan 08 '16 at 00:33
  • Yes, and `constexpr string s = "asdf"; //error`is a better illustration that constexpr require a literal type. – Don Slowik Jan 08 '16 at 20:06
11

In C++ constant integers are treated differently than other constant types. If they are initialized with a compile-time constant expression they can be used in a compile time expression. This was done so that array size could be a const int instead of #defined (like you were forced in C):

(Assume no VLA extensions)

const int s = 10;
int a[s];          // OK in C++
bolov
  • 72,283
  • 15
  • 145
  • 224
  • 3
    "and if you don't take their address" -- That's not part of the rule. You can take the address of `s`, and still use it as an array length. It's safe because even if you can take `s`'s address, you're not allowed to modify objects defined as `const` regardless of their types. –  Jan 07 '16 at 21:30
  • 1
    @hvd ty. That rule was for initializing in-class a non-static const integer data member. I thought it applied here too. – bolov Jan 07 '16 at 21:41