私は静的変数でテンプレートを宣言し、また、それを定義するヘッダファイルを持っている:このODR違反で噛まれないことを保証しますか?
/* my_header.hpp */
#ifndef MY_HEADER_HPP_
#define MY_HEADER_HPP_
#include <cstdio>
template<int n>
struct foo {
static int bar;
static void dump() { printf("%d\n", bar); }
};
template<int n>
int foo<n>::bar;
#endif // MY_HEADER_HPP_
このヘッダはmain.cpp
および共有ライブラリmylib
の両方が含まれます。特に、mylib_baz.hpp
にはこのテンプレートだけが含まれており、テンプレートの特殊化を変更する関数が宣言されています。
/* mylib_baz.hpp */
#ifndef MYLIB_BAZ_HPP_
#define MYLIB_BAZ_HPP_
#include "my_header.hpp"
typedef foo<123> mylib_foo;
void init_mylib_foo();
#endif // MYLIB_BAZ_HPP_
と
/* mylib_baz.cpp */
#include "mylib_baz.hpp"
void init_mylib_foo() {
mylib_foo::bar = 123;
mylib_foo::dump();
};
Iは(mylib_baz.o
を含む)mylib.so
を行うと、foo<123>::bar
のシンボルが存在し、弱い宣言。しかし、foo<123>::bar
のシンボルは、私のmain.o
にも弱い宣言されています。
/* main.cpp */
#include "my_header.hpp"
#include "mylib_baz.hpp"
int main() {
foo<123>::bar = 456;
foo<123>::dump(); /* outputs 456 */
init_mylib_foo(); /* outputs 123 */
foo<123>::dump(); /* outputs 123 -- is this guaranteed? */
}
私が一つの定義ルール(両方my_header.cpp
とmain.cpp
で定義されたfoo<123>::bar
)に違反していますことが表示されます。しかし、g ++とclangの両方でシンボルが弱(またはユニーク)であると宣言されているので、これで噛まれることはありません - すべてのアクセスはfoo<123>::bar
に変更されます。
質問1:これは偶然の一致です(多分ODRは、テンプレートの静的メンバのための動作の相違点)、または私は実際には標準でこの動作を保証するのですか?
質問2:私は観察している動作をどのように予測できましたか?つまり、正確にコンパイラがシンボルを弱く宣言するのは何ですか?
私は標準では「動作してはいけません」と言っていますが、あなたのリンカーは「それはOKです」と言います。 ODRに違反することは悪い考えです。コードはどこでも動作しません。 Cでは、複数の定義を動作させる '共通の拡張'があります([C言語のソースファイル間で変数を共有するにはどうすれば 'extern'を使用しますか?](http://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files-in-c/) - この機能は実際にはCとC++のコンパイラがリンカ技術を共有する機会があります) –
合意しました!私はこれもうまくいかないとはかなり確信していますが、私は本当になぜそれに私の指を置くことはできません。私の場合、私は '' bar''externを宣言し、 'mylib_baz.cpp'で定義しただけです(そして、そうするべきです)。しかし、私はもっと深く掘り下げて、私が観察している振る舞いの背後にある論理的根拠を見るのは本当に興味があります。 – FreenodeForsakeMe
"foo <123> :: barはmy_header.cppとmain.cppの両方で定義されています" ...何?私はそれがあなたが言及したものではない一つの場所で定義されているのを見ています: 'my_header.hpp'。それは一つの定義です。 – Barry