問題タブ [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++ - クラス名を指定せずにテンプレートを特殊化する方法は?
debug
オブジェクトに関する情報を出力する関数を作成したいと考えています。私のシステムには、さまざまな種類のオブジェクトが含まれています。それらのいくつかには、他のオブジェクトが含まれています。
関数に引数のメンバーがある場合はそのメンバーを出力するname
か、引数のメンバーがある場合はそれをデバッグするcontents
ようにします。次のコードを思いつきました:
pack
ここで、とのコードline
はほぼ同じです! 同じコードを何度も書くのは避けたい:
ただし、この構文は、「単純な」オブジェクト (同じ署名を持つ) の関数テンプレートと競合します。
コードを書き直すにはどうすればよいですか? 私のプログラムのその部分はすでに非常に複雑であり、デバッグのためだけに何か(基本クラス、メンバー関数など)を追加するのは場違いに思えますdog
。human
c++ - C ++:異なる翻訳単位の同じ名前の異なるクラス
次の例を考えてみましょう。
コードは、コンパイラまたはリンカのエラーなしでコンパイルされます。しかし、出力は私にとって奇妙です:
最適化なしのFedorax86_64上のgcc(Red Hat 4.6.1-9)[ EG1 ]:
UsedClass 1(0x7fff0be4a6ff)doit hit
UsedClass 1(0x7fff0be4a72e)doit hit[EG1]と同じですが、-O2オプションが有効になっています[ EG2 ]:
UsedClass 2(0x7fffcef79fcf)doit hit
UsedClass 1(0x7fffcef79fff)doit hit最適化なしのWindowsXP32ビット上のmsvc2005(14.00.50727.762)[ EG3 ]:
UsedClass 1(0012FF5B)doit hit
UsedClass 1(0012FF67)doit hit[EG3]と同じですが、/ O2(または/ Ox)が有効になっています[ EG4 ]:
UsedClass 1(0012FF73)doit hit
UsedClass 1(0012FF7F)doit hit
リンカエラー(ODRルールに違反していると仮定)または[EG2]のような出力(コードがインライン化され、変換ユニットから何もエクスポートされず、ODRルールが保持される)のいずれかが予想されます。したがって、私の質問:
- なぜ出力[EG1]、[EG3]、[EG4]が可能なのですか?
- 異なるコンパイラから、または同じコンパイラからでも異なる結果が得られるのはなぜですか?そのため、この場合の動作は標準では何となく指定されていないと思います。
提案、コメント、標準的な解釈をありがとうございます。
更新
コンパイラの動作を理解したいと思います。より正確には、ODRに違反した場合にエラーが生成されない理由。仮説は、UsedClass1クラスとUsedClass2クラスのすべての関数がインラインとしてマークされているため(したがってC ++ 03 3.2に違反していないため)、リンカーはエラーを報告しませんが、この場合は[EG1]、[EG3]、[ EG4]奇妙に思えます。
c++ - インライン コンストラクターと 1 つの定義規則
次のソースファイルを検討してください 1.cpp
2.cpp
これらのファイルからコンパイルされたプログラムは整形式ですか? その出力には何が含まれるべきですか?
One Definition Rule の違反または出力 "1 2" によるリンカ エラーが予想されます。ただし、g++ 3.4 および VC 8.0 でコンパイルすると、「1 1」が出力されます。
これはどのように説明できますか?
c++ - pg:172-176.PartA.Interface Design Alternatives、Stroustrup-CPL-3E
172ページで、Stroustrupは次のようなことを行っています。
Q1。これは、最初の名前空間が(例として)user.hに挿入され、main.cpp(ドライバー)から含まれていることを意味しますか。2番目の名前空間をimplementer.hに追加し、parse.cppからインクルードしますか?これが彼が言う理由です:
「コンパイラには、名前空間の2つの定義の整合性をチェックするための十分な情報がありません」
- implementer.hとuser.hの両方を「パーサー実装」(parse.cpp)に含めることができないためですか?
174ページで、彼は次のことを行っています。
上の名前空間はimplementer.hに入り、下の名前空間はuser.hに入りますか?
彼の" dependency graph
"で、彼は明白なことを言い換えています。Makeを実行すると、 "Parser"(parser.cpp/implementer.h
)を変更すると、driver / main.cppが再構築されます-不必要ですか?
c++ - 変数を ODR 使用しない場合、翻訳単位間で複数の定義を使用できますか?
標準は、変数がodrで使用されていない場合、変数の定義の数に制限がないことを暗示しているようです(§3.2/3):
すべてのプログラムには、そのプログラムで ODR で使用されるすべての非インライン関数または変数の定義が 1 つだけ含まれている必要があります。診断は必要ありません。
翻訳単位内で変数を複数回定義することはできないと言っています(§3.2/1):
変換単位には、変数、関数、クラス型、列挙型、またはテンプレートの複数の定義が含まれてはなりません。
しかし、プログラム全体で、odr を使用しない変数に対する制限を見つけることができません。では、次のようなものをコンパイルできないのはなぜですか。
これらのファイルを g++ 4.6.3 でコンパイルおよびリンクすると、multiple definition of 'x'
. 正直なところ、私はこれを期待していますが、x
(私が知る限り)どこでも使用されていないため、標準がこれをどのように制限しているかわかりません。それとも未定義の動作ですか?
gcc - 複数の関数定義について警告するように GCC リンカーを取得する
私の小さな C ライブラリの例を考えてみましょう:
some_function() をパブリックに呼び出せるようにする予定です。ただし、ライブラリが必要とする外部ライブラリも、たまたま同じプロトタイプを持つ some_function() という関数を使用しているため、ライブラリは機能しません。ただし、GCC のリンカーは、some_function シンボルのソースがいくつあるかは気にしません。一見無作為に 1 つを選択し、外部ライブラリは独自の代わりに my some_function() を使用する場合と使用しない場合があります。これは非常識です。ライブラリが機能しないという事実ではありません。このライブラリは絶対に機能しないはずです。シンボル「some_function」のソースが 2 つありますが、リンカーはそれについて何もしません。そして、ご存知のように、私はGCCに慣れており、Cは一般的にデフォルトで病理学的に無謀であるため、それほど気にしません。方法があるに違いない ただし、同じシンボルに 2 つのソースがある場合にリンカに警告させるためです。-Wall -Wextra -Wshadow は既に試しましたが、警告は表示されません。
両方のライブラリが some_function() をエクスポートしたいので、-fvisibility=hidden はここでは役に立たないことに注意してください。一意のプレフィックスなしで関数呼び出しを行うことで、私を恥ずかしく思うことができます。あなたが正しい。それは間違い。私は気にしない。この間違いはリンカーによってキャッチできるため、キャッチする必要があります。リンカーがこの間違いをキャッチしない理由はありません。さらに、使用しているライブラリは奇妙な予期しないシンボルをエクスポートする可能性があり、他の誰かのライブラリがエクスポートするものを必ずしも制御できるとは限りません。それとプレフィックスは、プログラマーが停止して発火する前に、非常に一意にすることができます。
c++ - インライン化により、仮想関数をオーバーライドするテンプレート クラスの特殊なメンバー関数が見落とされる
偶然見つけた奇妙な例を皆さんと共有したいと思い、それで 2 日間考え続けました。
この例が機能するには、次のものが必要です。
- 三角形の仮想継承 (メンバー関数上
getAsString()
) - テンプレート クラスのメンバー関数の特殊化 (ここでは
Value<bool>::getAsString()
) 仮想関数をオーバーライドする - コンパイラによる (自動) インライン化
共通のインターフェース、つまり一連の仮想関数を仮想的に継承するテンプレート クラスから始めます。後で、これらの仮想機能の 1 つを特殊化します。インライン化すると、スペシャライゼーションが見過ごされる可能性があります。
次に、このクラスと、それ自体もテンプレート化する必要がValue
あるクラスのインターフェイスを継承する必要があります。Parameter
Value
今、 bool と等しい型の特殊化の前方宣言を与えないでください (!) 。
しかし、代わりに、このように定義するだけです...
..しかし、別のモジュールで(それは重要です)!
最後に、main()
何が起こっているかをテストする関数があります。
次のようにコードをコンパイルすると (test1.cpp と test2.cpp という名前の 2 つのモジュールにコードを配置し、後者には特殊化と必要な宣言のみが含まれます):
出力は
-O0
またはだけでコンパイルした場合、または-fno-inline
特殊化の前方宣言を行った場合、結果は次のようになります。
おかしいですね。
これまでの私の説明は次のとおりです。インライン化は最初のモジュール (test.cpp) で機能しています。必要なテンプレート関数はインスタンス化されますが、一部は への呼び出しでインライン化されてしまいますParameter<bool>::getAsString()
。一方、valbool
これは機能しませんでしたが、テンプレートはインスタンス化され、関数として使用されます。次に、リンカーは、インスタンス化されたテンプレート関数と、2 番目のモジュールで指定された特殊化されたテンプレート関数の両方を見つけ、後者を決定します。
どう思いますか?
- この動作はバグだと思いますか?
- どちらも仮想関数をオーバーライドしているのに、インライン化
Parameter<bool>::getAsString()
が機能するのに機能しないのはなぜですか?Value<bool>::getAsString()
c++ - static、constexpr、クラス内で初期化されたデータ メンバーで何ができますか?
これは、別の質問に与えられた短い回答と、それに関連する C++11 標準のいくつかの側面について、より完全な説明を求めているという点で、おそらく少し変わった質問です。
参照しやすいように、ここで参照されている質問を要約します。OP はクラスを定義します。
また、クラス内で初期化された静的データ メンバーの使用についてエラーが発生しないのはなぜだろうと考えています (ある本では、これは違法であると述べられています)。Johannes Schaubの答えは、次のように述べています。
- これは、 One Definition Ruleに違反しています。
- 診断は必要ありません。
この回答のソースと有効性に依存している限り、私は個人的にそれが難解すぎると感じているため、正直に嫌いです. 関連するのは § 9.4.2/4 のようです:
「プログラムには、 odr で使用される(3.2)静的データ メンバーの定義が 1 つだけ存在する必要があります。診断は必要ありません」 [強調は私のものです]
これにより、ポイントに少し近づきます。そして、これは § 3.2/2 がどのようにodr で使用される変数を定義するかです:
「潜在的に評価される式として現れる名前を持つ変数は、それが定数式 (5.19) に現れるための要件を満たし、左辺値から右辺値への変換 (4.1) がすぐに適用されるオブジェクトでない限り、odr 使用されます」 [強調は私のものです]
OPの質問では、変数は変数period
である定数式に現れるための要件を明確に満たしていconstexpr
ます。したがって、理由は確実に2 番目の条件にあるはずです: "そして、左辺値から右辺値への変換 (4.1) はすぐに適用されます"。
これは、標準の解釈に問題があるところです。この 2 番目の条件は、実際には何を意味するのでしょうか。それがカバーする状況は何ですか?関数から返された場合、静的constexpr
変数はodrで使用されない(したがって、クラス内で初期化できる)ということですか?
より一般的には、クラス内で初期化できるように、静的変数で何をすることが許可されていますか?constexpr
c++ - ヘッダーファイルでクラスを定義するときに、複数定義エラーが発生しないのはなぜですか?
正しく質問したかどうかはわかりませんが、説明させてください。
まず、宣言と定義の違いを説明するこの記事を読みました: http ://www.cprogramming.com/declare_vs_define.html
次に、以前の調査から、ヘッダーファイルで変数と関数を定義することは悪い習慣であることがわかっています。これは、リンクフェーズ中に、同じ名前に対して複数の定義があり、エラーが発生する可能性があるためです。
しかし、なぜこれがクラスで起こらないのですか?別のSOの回答( 定義と宣言の違いは何ですか?)によると、以下はクラスDEFINITIONになります。
上記の定義がヘッダーファイルにある場合。次に、おそらく、そのヘッダーを#includeする複数の.cppファイルを持つことができます。これは、クラスが複数の.oファイルでコンパイルされた後に複数回定義されていることを意味しますが、それほど問題は発生しないようです...
一方、ヘッダーファイルで定義されている関数の場合、明らかに問題が発生します...私が理解していることから...多分?
では、クラス定義の何がそんなに特別なのですか?