[解決済み] 静的な const int への未定義の参照
質問
今日、興味深い問題にぶつかりました。 この簡単な例について考えてみましょう。
template <typename T>
void foo(const T & a) { /* code */ }
// This would also fail
// void foo(const int & a) { /* code */ }
class Bar
{
public:
static const int kConst = 1;
void func()
{
foo(kConst); // This is the important line
}
};
int main()
{
Bar b;
b.func();
}
コンパイル時にエラーが出ます。
Undefined reference to 'Bar::kConst'
さて、これは間違いなく
static const int
がどこにも定義されていないからだと思います。私の理解では、コンパイラはコンパイル時に置換を行うことができ、定義を必要としないはずなので、これは意図的なものです。 しかし、この関数は
const int &
パラメータを取るので、置換を行わず、参照を優先しているようです。 次のように変更することで、この問題を解決することができます。
foo(static_cast<int>(kConst));
これは今、コンパイラが一時的にintを作り、その参照を渡すことを強制していると思いますが、これはコンパイル時に正常に行うことができます。
これは意図的なものなのでしょうか、それとも、このケースを処理できるように gcc に期待しすぎているのでしょうか。 あるいは、これは何らかの理由でやってはいけないことなのでしょうか。
どのように解決するのですか?
9.4.2/4では意図的なものだそうです。
静的データメンバが const integral 型または const enumeration 型である場合。 クラス定義でその宣言を指定することができます。 を指定することができます。 定数イニシャライザを指定することができます。 定数イニシャライザを指定することができます (5.19) その場合、そのメンバは に現れることができる。この場合 メンバは,依然として,名前空間スコープで定義されなければならない。 で使用される場合,そのメンバは,依然として名前空間スコープで定義されなければならない。 プログラム
静的データメンバをconst参照で渡すと、"use"する、3.2/2:
式は潜在的に評価される 式は評価される可能性がありますが、積分 定数式が必要な場合(5.19参照)、または 5.19参照)、sizeof演算子のオペランド(5.3.3)、またはtypeid演算子のオペランドであって のオペランドであり,かつ式 の lvalue を指定しない。 多相クラス型(5.2.8)のl値を指定しない。オブジェクト オブジェクトまたは非オーバーロード関数は その名前が評価される可能性のある式に現れる場合、オブジェクトまたはオーバーロードされていない関数が使用されます。 評価される可能性のある式にその名前が現れる場合,オブジェクト又はオーバーロードされていない関数が使用される。
つまり、実際には値で渡すときにも "use"を使うか、あるいは
static_cast
. ただ、GCCは一方のケースでは見逃してくれますが、もう一方のケースでは見逃してくれません。
[編集: gcc は C++0x ドラフトからのルールを適用しています: "潜在的に評価される式として名前が現れる変数またはオーバーロードされていない関数は、それが定数式に現れるための要件 (5.19) を満たすオブジェクトで、lvalue-rvalue 変換 (4.1) が直ちに適用されない限り、odor 使用となります)"。静的キャストはlvalue-rvalue変換を即座に行うので、C++0xでは"used"ではありません]。
const参照の実用的な問題点は
foo
がその引数のアドレスを取得し、例えばグローバルに格納されている別の呼び出しからの引数のアドレスと比較する権利の範囲内にあることです。静的データメンバは一意なオブジェクトなので、もしあなたが
foo(kConst)
を呼び出すと、渡されるオブジェクトのアドレスはそれぞれのケースで同じでなければならないことを意味します。AFAIK GCCは、オブジェクトが1つの(そして唯一の)TUで定義されていない限り、それを手配することができません。
OK、ではこの場合
foo
はテンプレートであり、したがってその定義はすべての TU で見ることができるので、おそらくコンパイラは理論的にはそのアドレスで何かをするリスクを除外することができます。しかし、一般的には、存在しないオブジェクトのアドレスや参照を取るべきではありません;-)。
関連
-
[解決済み】C++でint型に無限大を設定する
-
[解決済み】C++でユーザー入力を待つ【重複あり
-
[解決済み] 既に.objで定義されている-二重包含はない
-
[解決済み】「Expected '(' for function-style cast or type construction」エラーの意味とは?
-
[解決済み] C++でintをstringに変換する最も簡単な方法
-
[解決済み] const int*、const int * const、int const *の違いは何ですか?
-
[解決済み] 未定義の動作とシーケンスポイント
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
-
[解決済み】vtableへの未定義の参照
-
[解決済み] publicなconstメソッドがprivateな時に呼び出されないのはなぜですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 unsigned int vs. size_t
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み】C++ 非推奨の文字列定数から「char*」への変換について
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み】cc1plus:エラー:g++で認識されないコマンドラインオプション"-std=c++11"
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み】Visual Studio 2013および2015でC++コンパイラーエラーC2280「削除された関数を参照しようとした」が発生する
-
[解決済み】リンカーエラーです。"リンカ入力ファイルはリンクが行われていないため未使用"、そのファイル内の関数への未定義参照
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む