2015-12-23 19 views
16

残念ながら、私はconstexpr、ヘッダーファイルで宣言されたグローバル定数とodrについて多少混乱しています。ヘッダーファイルとodrのconstexprグローバル定数

要するに

:私たちは、私がしたい場合

constexpr MyClass const MyClassObj() { return MyClass {}; } 
constexpr char const * Hello() { return "Hello"; } 

は、ヘッダファイル でグローバルを定義するための

constexpr MyClass const kMyClassObj = MyClass {}; 
constexpr char const * kHello = "Hello"; 

以上が望ましいことをここ

https://isocpp.org/files/papers/n4147.pdf

から結論付けることができますそれらを "ちょうど使用する"にはグローバルに宣言された/定義されたエンティティは考えたくありませんどのように私はそれらを使用しますか?

+0

名前空間スコープの定数には内部結合があります。この問題は 'inline'関数でそのような定数を評価するときに発生します。 –

+0

あなたはどのプラットフォームにいますか? –

+1

@ JohnB: 'constexpr char const * const kHello =" Hello ";'代わりに - + 11では 'constexpr'は' const'を意味しますが、C++では14 。 ODRがこの問題のC++ 14と大きく異なるのかどうかはわかりませんが、とにかく私の経験ではこれについてコンパイラの警告を得ることができます。 –

答えて

12

注:C++ 17では、variables as inlineを宣言できます。


TL; DR:あなたは(非常に)安全側になりたい場合は、constexprの機能を持って行きます。しかし、これらのオブジェクトに対して簡単な操作を行い、その価値にのみ関心がある場合や、以下に示す危険なシナリオでは使用しない場合は、本質的に必要ではありません。

根本的な問題は、あなたのような名前空間のスコープの変数が内部リンケージ([basic.link]/(3.2))を持っているということです。これは、対応するヘッダーをコンパイルする各翻訳単位が異なるエンティティ(つまりシンボル)を観察することを意味します。

ここで、これらのオブジェクトを使用しているヘッダーにテンプレートまたはインライン関数があるとします。 ODRは、このシナリオについて非常に正確である - [basic.def.odr]/6:私たちはconstexprを話しているので、

enter image description here

「定数式で初期化は、」確かに、満たされています。だから"あなたはサルについては、D"のすべての定義でオブジェクトが同じ値を持っています。

"オブジェクトはodr-usedではありません"はおそらく疑わしい条件です。基本的に、それはあなたが順番に

  • あなたが参照にそれを結合しないことを意味し、シンボル、(=>あなたがそれを転送しません!)などの変数のランタイム存在を必要としないことが必要です

  • あなたは、明示的にも暗示的にもそのアドレスをとらない。

第ルールの唯一の例外

は、二つの上記のルールが得glvalueために違反していない限り、添字操作内部暗黙のアドレスを取ることができる配列です。

名潜在的に評価された式exexでODR-使用されているとして表示され、変数x 左辺値ツー右辺値の変換を適用しない限り:より正確には、ODR-使用が[basic.def.odr]/3によって支配され

(4.1)〜xは、非自明な関数を呼び出さない定数式(5.20)を生成し、xがオブジェクトである場合、の潜在的結果のセットの要素です。ここで、左辺 - 数値変換(4.1)はに適用されますまたはeは、破棄された値の式です(句 5)。

任意のconstexprにl-t-rを適用すると、最初の部分の必要に応じて動作します。 2番目の部分は、実際のオブジェクトではなく、として変数を使用する必要があります。つまり、最終的に破棄されるか直接評価され、上記の経験則が与えられます。

インライン関数やテンプレートなどの内部で変数のodr-useを使用しないようにすると、問題ありません。しかし、対応するconstexpr関数の戻り値を使用すると、prvaluesはすでに値/リテラル​​(オブジェクトではない)のように動作しており、constexpr関数はインラインであり、ODRに違反しないので心配する必要はありません(ifそこにはconstexpr変数を使用しないでください!)。

+0

の映画を見たことがありますか? "あなたは基本的に、対応するconstexpr関数の戻り値ではできなかった操作を実行しました。本当に。実際には、参照バインディング(転送参照または定数参照)が重要な問題です。 –

+0

したがって、私が正しくあなたを理解していれば、「価値を返す」アプローチを使用すれば、私が考えるより少ないと思うという私の前提は正しいのですか?私の問題は:私は問題を理解していると思うが、私は偶然の間違いを避けるのに十分な流暢さを感じていない。 – JohnB

+0

@ T.C。さて、正確に言うと、操作は "左辺値への参照"を "値"にバインドすることですが、それは不明です:o) – Columbo

関連する問題