54

次の単純なプログラムをコンパイルしていますg++-4.6.1 --std=c++0x

#include <algorithm>

struct S
{
    static constexpr int X = 10;
};

int main()
{
    return std::min(S::X, 0);
};

次のリンカ エラーが発生します。

/tmp/ccBj7UBt.o: In function `main':
scratch.cpp:(.text+0x17): undefined reference to `S::X'
collect2: ld returned 1 exit status

インラインで定義された静的メンバーにはシンボルが定義されていないことを認識していますが、使用するconstexprとコンパイラにシンボルを常に式として扱うように指示したという (おそらく欠陥のある) 印象を受けました。そのため、コンパイラは、シンボルへの参照を渡すことは正当ではないことを認識しますS::X(同じ理由で、リテラルへの参照を受け取ることはできません10)。

ただし、S が名前空間として宣言されている場合、つまり「構造体 S」ではなく「名前空間 S」である場合、すべて正常にリンクされます。

これはg++バグですか、それともこの煩わしさを回避するためにトリックを使用する必要がありますか?

4

6 に答える 6

38

これはバグではないと思います。を に変更しconstexprconstも、まったく同じエラーで失敗します。

を宣言しましたがS::X、どこにも定義していないため、ストレージがありません。そのアドレスを知る必要がある何かを行う場合は、それをどこかで定義する必要があります。

例:

int main() {
      int i = S::X; // fine
      foo<S::X>(); // fine
      const int *p = &S::X; // needs definition
      return std::min(S::X, 0); // needs it also
}

この理由は、コンパイル時に評価constexpr できるためですが、そのように評価する必要はなく、実行時にも同様に発生する可能性があります。「コンパイラーが常にシンボルを式として扱う」ように指示するのではなく、コンパイラーがそのように感じた場合、そうすることは賢明で許容されることを示唆しています。

于 2011-12-09T23:28:32.727 に答える
5

C++ 標準 (最新のワーキング ドラフト) では、次のように述べられています。

const名前空間スコープ (3.3.6) を持つ名前は、[...] 明示的に宣言されているかconstexpr、明示的に宣言されておらず、外部リンケージを持つように事前に宣言されていない[...] 変数の名前である場合、内部リンケージexternを持ちます [...]。

「リンケージ」は次のように定義されます。

別のスコープの宣言によって導入された名前と同じオブジェクト、参照、関数、型、テンプレート、名前空間、または値を示す可能性がある場合、その名前はリンケージを持つと言われます。

— 名前に外部リンケージがある場合、それが示すエンティティは、他の翻訳単位のスコープまたは同じ翻訳単位の他のスコープからの名前によって参照できます。

— 名前に内部リンケージがある場合、それが示すエンティティは、同じ翻訳単位内の他のスコープからの名前によって参照できます。

— 名前にリンケージがない場合、それが示すエンティティは、他のスコープの名前で参照できません。

したがって、 の場合namespace S外部リンケージがあり、 の場合struct S内部リンケージがあります。

外部リンケージを持つシンボルは、何らかの翻訳単位でシ​​ンボルを明示的に定義する必要があります。

于 2014-06-24T10:14:27.907 に答える
0

あなたの理解constexprは間違っています。宣言された左辺値 constexprは依然として左辺値であり、宣言された関数 constexprは依然として関数です。また、関数に参照パラメーターがあり、左辺値が渡される場合、言語では、参照がその左辺値を参照する必要があり、それ以外は何も必要ありません。( type の変数に適用すると、と plain intの違いはほとんどありません。)constexprconst

于 2014-06-20T12:46:39.850 に答える