3

When the constexpr was introduced to C++ I started to write my compile time constants as constexpr static member variables instead of using the enum hack.

So I know about the subtle difference that you cannot take the address of a constant defined with enum, where in the constexpr case you can. Since you don't want to do that, so it's fine. But now I stumbled upon some code where I'm not sure whether you might accidentally take the address.

#include <iostream>

struct A
{
    constexpr static unsigned c1 = 1;
    enum{ c2 = 2 };
};

template<typename T>
auto foo(T&& p)
{
    return p;
}

int main()
{
    std::cout << foo(A::c1) << " " << foo(A::c2) << std::endl;
    return 0;
}

gcc 7 and clang 4 will compile this code just fine, where any older versions of these compilers will complain about an undefined reference of A::c1.

If I understand this correctly, the function foo takes the A::c1 expression as some kind of reference and thus needs to take its address, which leads to the undefined reference.

What is the correct behavior? Does the standard require me to define the member variable just to be able to use them in the context of perfect forwarding?

Edit: I just noticed, gcc 7 as well as clang 4 will also complain about the undefined reference if you use -std=c++14 instead of -std=c++1z. So was there a related change in the standard?

Morwenn
  • 21,684
  • 12
  • 93
  • 152
mic
  • 821
  • 6
  • 18
  • Possible duplicate of [C++ Linker Error With Class static constexpr](http://stackoverflow.com/questions/8452952/c-linker-error-with-class-static-constexpr) – m.s. Nov 05 '16 at 14:07
  • @m.s. much may have changed since C++11, as that question is tagged. – krzaq Nov 05 '16 at 14:09
  • 2
    See [this answer](http://stackoverflow.com/a/38043566/440558) about inline member variable definitions. – Some programmer dude Nov 05 '16 at 14:12
  • @m.s. I would say the answer you linked does not answer my question, since I'm not asking for a fix. My question is about whether the standard really requires me to define such members in a separate compilation unit just to be able to use it in the context of perfect forwarding. But the [link](http://stackoverflow.com/a/38043566/440558) of Some programmer dude gives some insight. – mic Nov 05 '16 at 16:02
  • Yes, reference binding means odr-use, and anything that's odr-used needs to have a definition. – T.C. Nov 05 '16 at 20:16

0 Answers0