2016-06-17 5 views
3

:私はval宣言からconstexprのコメントを解除した場合、このプログラムは、(++グラムでのみ-O0に、常に打ち鳴らすと)undefined reference to 'A::a'とリンクに失敗しone-definition-rule-use(odr-use)はコンテキストに依存するのはなぜですか?以下のコードを考える

#include <iostream> 

struct A { 
    static constexpr float a = 2.0f; 
}; 

// non-const reference to make it more explicit - same behaviour 
template<class T> constexpr inline T square(T& x) 
{ 
    return x * x; 
} 

int main() { 
    /*constexpr*/ float val = square(A::a); 
    std::cout << val; 
} 

は、しかし、それが適切にリンクします。

これまで私はconstexprをユニットファイルの1つで明示的な定義なしにodr-使用できないことを理解していますが、constexprに割り当てている間になぜ機能しないのか分かりません。

この2つのケースは、状況によって異なって扱われるようです。しかし、なぜ?どちらの場合でもコンパイラはコンパイル時にこの関数を評価するべきではありませんか?

+0

投稿したスニペットは、GCCとCLANGの両方でうまくコンパイルされます。 – 101010

+0

タイトルに珍しい頭文字語を使用しないでください。 – UmNyobe

+0

@ 101010問題を見るために 'constexpr float val = square(A :: a);'から 'constexpr'を削除する – marcinj

答えて

4

なぜodr-useはコンテキストに依存しますか?

これはありません。 square(A::a) odr-A::a、期間を使用します。

しかし、ほとんどのODR違反は診断する必要はなく、これも例外ではありません。

コンパイラは、どちらの場合でもコンパイル時にこの関数を評価するべきではありませんか?

変数constexprの初期化子は、コンパイル時に評価する必要があります。 (まあまあではありませんが、コンパイラは、それが有効な定数式であると判断できる点まで評価しなければなりません。その時点で、すべてのことを行うだけです)。constexprローカル変数の場合、そのような保証はありません。

+1

だから私はむしろ "なぜコンパイル時にodr-useが動作するのですか?"と尋ねるべきです。たとえばポインタがどこを指しているでしょうか?プログラムが実行されていません。いくつかのコンパイラ構造を指していますか? なぜこのような場合に失敗しないのですか?なぜ標準がそのような構成を許しているのですか? – pkubik

+0

@pkubik確かに、質問する質問を作成することができます。それをもう少し洗練させて、理想的には本当の問題に付けてください。しかし、この質問はそれではありません! – Yakk