実際のプロジェクトで見られる問題に基づいて考案した次の簡単なクラスについて考えてみます。constexpr
Tripleは、クラスFooのインナーで使用するクイックボイラープレートタイプです。
#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_;
};
次にmain()
、のパブリック内部を使用する関数をconstexpr
次のように作成Foo
すると、リンクに失敗します(Windows7ではmingw-x86-64を介してg++ 4.7.0を使用)。
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): `Foo :: defaultTriple'への未定義の参照collect2.exe:エラー:ldが1つの終了ステータスを返しました
しかし、私が書くと
cout << Triple{Foo::defaultTriple} << endl
単にではなく
cout << Foo::defaultTriple << endl
リンクして正常に実行されます。前者はコンパイル時リテラルが意図されたものであることをより明確に表現していることがわかりますが、後者がうまく機能しないことにまだ驚いています。constexpr
これはコンパイラのバグですか、それとも最初の例だけが機能するというルールに基づく理由がありますか?
より多くの洞察を得るために他のコンパイラを試してみますが、現在、GCC4.7.0は私がアクセスできる唯一のコンパイラですconstexpr
。
constexpr
ポッドの式は、明示的なリテラルラッパーがなくても正常に機能することにも注意してください。たとえば、cout << Foo::defaultPOD
問題が発生したことはありません。