7

ここから:

struct piecewise_construct_t {};
constexpr piecewise_construct_t piecewise_construct = {};

const int magic_number = 42;

inline std::tuple<int> make_magic() {
return std::tuple<int>( piecewise_construct, magic_number );
}

この関数は、ODR ([basic.def.odr] §3.2/6) に 2 回違反します。これは、コンストラクター 2 の引数のどちらも左辺値から右辺値への変換を受け取らないためです。したがって、それらはアドレスで渡されますが、const (および constexpr) は内部リンケージを意味するため、アドレスは TU に依存します。

最初はそうだと思ったのですが、問題はmagic_number内部リンケージです。内部リンケージがあるため、本質的にmagic_numberは、それらが異なる翻訳単位の異なる変数であるかのように扱われ、したがって同じ変数の複数の定義としてではありませんか? C++ 標準の最新のワーキング ドラフトの引用を使用して、誰かがこれを指定できますか?

4

1 に答える 1

8

問題はmake_magic. [basic.def.odr]/p6:

各定義が異なる翻訳単位に現れ、定義が次の要件を満たしている場合、プログラム内に ... 外部リンケージ (7.1.2) を持つインライン関数 ... の複数の定義があってもかまいません。D複数の翻訳単位で定義された名前のエンティティが与えられた場合、

  • の各定義はD、同じ一連のトークンで構成されます。と
  • の各定義においてD、対応する名前は、3.4 に従って検索され、 の定義内で定義されたエンティティをD参照するか、オーバーロードの解決後 (13.3) および部分的なテンプレートの特殊化の一致後 (14.8.3) に同じエンティティを参照する必要があります。ただしconst、オブジェクトが のすべての定義で同じリテラル型をD持ち、オブジェクトが定数式 (5.20) で初期化され、オブジェクトがodr-used であり、オブジェクトは のすべての定義で同じ値を持ちますD。と
  • [...]

piecewise_constructmagic_numberには内部リンケージがあるため、インライン関数make_magicが複数の翻訳単位で定義されている場合、名前piecewise_constructmagic_numberは異なるエンティティを参照します。つまり、TU 1make_magicは TU 1 と をpiecewise_construct参照し、TU 2 はmagic_numberTU 2とmake_magicを参照します。問題のコンストラクターは参照によって引数を取るため、左辺値から右辺値への変換は実行されず、オブジェクトは ODR で使用され、2 番目の箇条書きの例外は適用されず、ODR 違反が発生します。piecewise_constructmagic_numbertuple

(ちなみに、 にはコンストラクタstd::tupleがありませんpiecewise_construct。また、いずれにしても、そのようなコンストラクタはプレーンintではなくタプルを引数として取ると思われますが、それは論文が作成しようとしている点と直交しています。)

于 2015-07-27T02:18:50.357 に答える