4

私が開発しているアプリケーションには、次のようなテンプレート関数があります。

template<class T>
void CIO::writeln(T item)
{
    stringstream ss;
    ss << item << '\r' << endl;
    write(ss.str());
}

この関数は、T = const char* および T=std::string を使用して、いくつかの場所から呼び出されます。CodeSourcery Lite 2008.03-41 (GCC 4.3.2) を使用すると、これは -O3 コンパイラ フラグで正常にコンパイルおよびリンクされます。ただ、CodeSourcery Lite 2012.03-57(GCC 4.6.3)に変更したので、-O3でコンパイルはOKなのですが、その後でリンクに失敗しundefined reference to void CIO::writeln<std::string>(std::string)ます。-O2 以下ですべて問題なく、リンクは成功します。

これを詳しく調べたところ、アセンブリの出力で何か奇妙なことがわかりました。-O2 でコンパイルすると、関数の 2 つの特殊化が見つかります。1 つは const char* ( _ZN3CIO7writelnIPKcEEvT_) 用で、もう 1 つは std::string ( _ZN3CIO7writelnISsEEvT_) 用ですが、 -O3 でコンパイルすると、2 番目の特殊化が欠落しており、これがリンク エラーを説明しています。

これはコンパイラのバグですか? これは奇妙な最適化が悪に変わったのでしょうか?

前もって感謝します!

編集: この関数はソース ファイルにあります。Mike Seymour のコメントに従って、ヘッダーに移動したところ、すべて問題ありません。私はこれにもっと早く気づくべきだったことを認めます。とはいえ、最適化フラグによって言語ルールがチェックされたりチェックされなかったりするのは恐ろしいことです。

4

1 に答える 1

1

他の回答とは異なり、これはおそらくコンパイラのバグではありません。

によって有効になる最適化の 1 つは、-O3関数のインライン化です。私が考えていることは次のとおりです。

CIO::writelnソース ファイル 1 は、その定義を利用できない状態で呼び出しています。オブジェクトファイル 1 にコンパイルされます。

CIO::writelnソース ファイル 2 は、その定義を使用できる状態で呼び出しています。オブジェクトファイル 2 にコンパイルされます。

オブジェクト ファイル 1 は、オブジェクト ファイル 2 に の定義が含まれている場合にのみ使用できますCIO::writeln。ソース ファイル 2 の呼び出しがインライン化された場合、オブジェクト ファイル 2 にはその定義が含まれません。呼び出しがインライン化されない場合、定義が使用可能になります。

コメントに示されている解決策は、定義をヘッダー ファイルに移動することです。正しいです。

于 2013-11-12T12:40:14.700 に答える