Consider the following simple classes that I invented based on the problems that I see with a real project. Triple is a quick boiler plate type for use with the internal constexpr in the Foo class:
#include <iostream> class Triple { public: friend std::ostream & operator <<(std::ostream & o, Triple const & t); constexpr Triple() : a_(0), b_(0), c_(0) { } constexpr Triple(Triple const & other) = default; constexpr Triple(double a, double b, double c) : a_(a), b_(b), c_(c) { } ~Triple() = default; private: double a_, b_, c_; }; std::ostream & operator <<(std::ostream & o, Triple const & t) { o << "(" << t.a_ << ", " << t.b_ << ", " << t.c_ << ")"; return o; } class Foo { public: Foo() : triple_(defaultTriple) { } Triple const & triple() const { return triple_; } Triple & triple() { return triple_; } constexpr static float defaultPOD{10}; constexpr static Triple defaultTriple{11.0, 22.0, 33.0}; private: Triple triple_; };
If I then write the main() function to use the public internal constexpr from Foo , as shown below, it will not be able to reference (using g ++ 4.7.0, via mingw-x86-64 on Windows 7):
int main(int argc, char ** argv) { using std::cout; using std::endl; cout << Foo::defaultPOD << endl; cout << Foo::defaultTriple << endl; }
$ g ++ -o test -O3 --std = c ++ 11 test.cpp
e: \ temp \ ccwJqI4p.o: test.cpp :(. text.startup + 0x28): undefined reference to `Foo :: defaultTriple 'collect2.exe: error: ld returned 1 exit status
However, if I write
cout << Triple{Foo::defaultTriple} << endl
instead of simple
cout << Foo::defaultTriple << endl
it will communicate and work fine. I see that the first of them expresses more explicitly what is intended for compilation-time, but I am still surprised that the latter will not work. Is this a compiler error, or is there a rule-based reason for constexpr that only the first example should work?
I would try other compilers to get more information, but currently GCC 4.7.0 is the only one I have access to that supports constexpr .
Note also that the expression for pod constexpr works fine without an explicit literal shell, for example. cout << Foo::defaultPOD never bothered me.