問題タブ [one-definition-rule]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - ODR で使用される定義についての少しの誤解
ODR で使用される変数の定義は次のとおりです。
名前が潜在的に評価される式 ex として現れる変数 x は、x が定数式 (5.19) に出現するための要件を満たさない限り、odr 使用されます。x がオブジェクトである場合、ex は、の潜在的な結果のセットの要素です。左辺値から右辺値への変換 (4.1) が e に適用される式 e、または e が破棄値式 (節 5) である式 e。
私が理解している限り、評価されるex
可能x
性のあるオペランドとして、たとえば、x++
または
しかし、私はその場合に何が起こっているのか理解できませんでしたe
。
c++ - static constexpr float メンバーにアクセスするときの未定義の参照
このコードは機能します:
しかし、次のように変更int
するfloat
と、エラーが発生します。
/tmp/main-272d80.o: 関数
main': main.cpp:(.text+0xe): undefined reference to
Blob::a' 内
そのように a を使用できないのはなぜconstexpr float
ですか?
コンパイラ: Ubuntu clang バージョン 3.5.0-4ubuntu2 (tags/RELEASE_350/final)
gcc バージョン 4.9.1 (Ubuntu 4.9.1-16ubuntu6) でテストされ、エラーはありませんでした。
編集:
-O1、-O2、-O3、または -Os を使用するとコンパイルされますが、-O0 で失敗します
c++ - C++ では、未使用の変数に複数の定義を含めることができますか?
与えられた 1 つのソース ファイル
と別のソースファイル
実装は一般的にこれを拒否します。使用されていませんが、それは私には理にかなっていますa
。
ただし、これがエラーであると標準が示している場所を見つけることができません。
Cでは、これは(私のものを強調)でカバーされています:
6.9 外部定義
5外部定義は、関数 (インライン定義以外) またはオブジェクトの定義でもある外部宣言です。
sizeof
外部リンケージで宣言された識別子が式で使用される場合 (結果が整数定数である演算子のオペランドの一部として以外)、プログラム全体のどこかに、識別子の外部定義が 1 つだけ存在する必要があります。それ以外の場合は、1 つしか存在しないものとします。
これは制約の外側に現れるため、C では動作は単純に定義されていません。実装はそれを拒否することが許可されています。または、警告なしで静かに受け入れることが許可されています。この場合、動作については保証されません。意図はC++でも同じだと確信しています。
[basic.def.odr] の C++ 標準の「プログラム全体のどこかに、識別子の外部定義が 1 つだけ存在する」に相当するものを見つけることができます。
3.2 1 つの定義規則 [basic.def.odr]
4 すべてのプログラムには、そのプログラムで ODR で使用されるすべての非インライン関数または変数の定義が 1 つだけ含まれている必要があります。診断は必要ありません。[...]
しかし、odr で使用されていないオブジェクトまたは関数をカバーする文言を見つけることができません。標準は、これがエラーであることをどこかに明記していますか? もしそうなら、どこですか?
[basic.def.odr] には、通常、p6 で複数の定義を持つことができる特定の種類のエンティティに対する制限も含まれており、事実上、すべての定義が同一でなければならないことが述べられています。しかし、それは「クラス型(条項9)、列挙型(7.2)、外部リンケージを持つインライン関数(7.1.2)、クラステンプレート(条項14)、非静的関数テンプレート(14.5.6)、静的データ」のみをカバーしていますクラス テンプレートのメンバー (14.5.1.3)、クラス テンプレートのメンバー関数 (14.5.1.1)、または一部のテンプレート パラメーターが指定されていないテンプレートの特殊化 (14.7、14.5.5)」、グローバル変数ではなく、さらに、定義は一致します。
[dcl.link] がこれに対処するのではないかと思いましたが、そうではありません。最も近いのは、[basic.def.odr] を参照するだけの C リンケージを持つエンティティに関するメモです。
7.5 リンケージ仕様 [dcl.link]
6 [...] [注: C 言語リンケージを持つ特定の名前を持つエンティティーの定義は 1 つだけプログラムに現れる場合があります (3.2 を参照)。これは、そのようなエンティティを複数の名前空間スコープで定義してはならないことを意味します。--文末] [...]
これが間違いであることは明らかなので、私は単に何かを見落としているとほぼ確信しています。
c++ - インラインおよび constexpr 関数の場合、「ODR に従う」とはどういう意味ですか?
constexpr とインライン関数は 1 つの定義規則に従うことを読みましたが、それらの定義は同一でなければなりません。だから私はそれを試します:
エラー: 'void foo()' の再定義、
および
エラー: 'constexpr int foo()' の再定義
では、constexpr と inline 関数が ODR に従うことができるということは、正確には何を意味するのでしょうか?
c++ - 公開インターフェースと ODR でのメンバーの非表示
クライアント コードから隠したい内部構造を持つライブラリに複数のクラスがあります。クライアントの観点からは、各クラスはライブラリ クラスからクエリされ、不透明なポインターとしてのみ使用されます。例は次のとおりです。
実装側では、 SomeSystem には、呼び出し元には表示されない複数のメンバーがあります。これはすべて問題ありませんが、不格好な使用構文はあまり好きではありません。
別のアプローチはこれです:
使用法コード:
doSomething
と呼ばれるグローバル メソッドを使用doSomethingElse
して、別の型でも が定義されている場合は、関数のオーバーロードに依存することもできますdoSomething
。ただし、この場合、IDE で SomeSystem のすべての「メンバー」を見つけるのは困難です。
私は実際にメンバー関数を使用したくなる:
使用法コード:
最後のスニペットは私には良さそうに見えますが、 SomeSystem はもはや不透明なポインターではなく、実際にメンバーを定義しています。私はこれを少し警戒しています。潜在的な問題の 1 つは、1 つの定義ルールです。ただし、クラスの「パブリック」定義と「プライベート」定義は、異なる翻訳単位からしか見えません。ここに隠された他の悪いことはありますか?クライアント コードがスタックまたは new を使用して SomeSystem をインスタンス化しようとすると、明らかにプログラムがクラッシュします。しかし、私はそれを喜んで受け入れます。おそらく、パブリック インターフェイスでプライベート コンストラクターを提供することで、これを回避できます。
もちろん、別のアプローチは、純粋仮想メソッドを使用して抽象クラスを定義することです。ただし、絶対に必要でない場合に備えて、このオーバーヘッドは避けたいと思います。
編集:
明確にするために、クライアントがクラスをインスタンス化しないため、実装が使用するものとは異なるクラスの定義 (一部のメンバーが欠落している) を含むパブリックヘッダーをクライアントに含めることが合法であるかどうか疑問に思っています。
公開ヘッダー:
プライベート ヘッダー:
プライベート ソース (プライベート ヘッダーを含む):
これはテスト時に機能しますが、何らかの形で標準に違反しているかどうかはわかりません。2 つのヘッダーが同じ翻訳単位に含まれることはありません。
c++ - std::make_unique、匿名名前空間および ODR
次のテストケースを検討してください (LLVM ソースから縮小):
と
これは 1 つの定義規則に違反していますか?
gcc-6 は現在、次のように考えています。
c++ - 複数のクラスでスタックを実装する場合の 1 つの定義規則 (ODR)
単純なスタック実装が機能していないようです。私は単純に、2 つの異なるクラス (クラス B とクラス C) を取得して、3 番目のクラス (クラス A) によって管理されている同じスタック内の要素をプッシュおよび印刷できるようにしようとしています。
A.cpp
ああ
B.cpp
C.cpp
私は 1 つの定義ルールを破っていると思います。私は正しいですか?