0

The code below triggers error with gcc 'undefined reference Foo::d' and 'undefined reference Foo::i'. Strangely, it happens only if I compile it in -Og, or -O1 optimization mode, but not with -O2 or -O3. Moreover, if I pass constexpr double as parameter for int& and vice versa (see last too calls) -- it does not trigger error.

#include <stdio.h> class Foo { public: static constexpr double d = 10.0; static constexpr int i = 10; }; //class Foo void print_double_ref(const double& v) { printf("v = %g\n", v); } void print_int_ref(const int& n) { printf("n = %i\n", n); } int main() { Foo a; //This part triggers link error with -Og, -O1 //No error with -O2, -O3 print_double_ref(a.d); print_int_ref(a.i); //This part does not trigger link error with -Og, -O1 print_int_ref(a.d); print_double_ref(a.i); } 

I understand, that problem is somehow related to declaring argument of functions print_double_ref and print_int_ref as references. The questions are:

  1. Why link error in -Og and -O1 modes only?
  2. Why passing constexpr double as parameter for const int& (or constexpr int as parameter for const double& does not produce error?

Update: I know that for static const members one should initialize them outside the class. However, constexpr variables must be defined at the point of declaration. Why such a construct is allowed to be compiled then?

8
  • 1
    I think the proper syntax to avoid linker errors is static inline .... See here: static members. Commented Sep 7, 2023 at 12:15
  • This is related to the so called ODR-usage (to put it simple: taking address via pointer or reference) of a variable that is only declared, but not defined. Split definition and declaration or make the variable inline. See this: stackoverflow.com/questions/272900/… Commented Sep 7, 2023 at 12:18
  • Can't repro: godbolt.org/z/jfd6177sa you should provide more detail about build process. Commented Sep 7, 2023 at 12:53
  • I now see here, that static constexpr int i = 10; should imply inline and is therefore a definition (not only a declaration). So there should be no linker error. That's from c++17. Which version of c++ do you use ? Commented Sep 7, 2023 at 13:32
  • 1
    @one_two_three still the rule about static class member still applies, see stackoverflow.com/a/28446388/4885321 Note: "The member shall still be defined in a namespace scope if it is odr-used" Commented Sep 7, 2023 at 14:47

1 Answer 1

2

The program does not contain definitions of Foo::i and Foo::d (only declarations) and these things are being ODR-used. The behaviour is thus undefined.

Passing to a wrong reference parameter type does not trigger binding a reference, but rather creation of a temporary, to which a reference is then bound. So no ODR-use in this case.

Sign up to request clarification or add additional context in comments.

2 Comments

I understand it for static const double, but not for static constexpr double -- there is no way to split constexpr declaration and definition.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.