私が取り組んでいるプロジェクトのシリアル化コードのビットには、サイズがコンパイラに依存する型があります。これに対処するために、うまく機能するテンプレートの特殊化を使用することにしました。すべてがコンパイル時に解決されます。コードは次のようになります (実際のコードではなく、単なる例です)。
template <int size>
void
special_function()
{
std::cout << "Called without specialization: " << size << std::endl;
}
template <>
void
special_function<4>()
{
std::cout << "dword" << std::endl;
}
template <>
void
special_function<8>()
{
std::cout << "qword" << std::endl;
}
int
main()
{
special_function<sizeof(int)>();
return 0;
}
私の 32 ビット システムでは、上記のプログラムを実行するdword
と、期待どおりに出力されます。しかし、単に実行するのではなく、このように実行することの要点はif (sizeof(int) == 4) { ... } else if ...
、コンパイラが適切な関数のコードのみを生成することを望んでいたことです。このプログラムで呼び出されるのは だけなのでspecial_function<4>
、コンパイラ (この場合は gcc 4.1.2、x86 Linux) によって生成されるのはこれだけだと予想しました。
しかし、それは観測された動作ではありません。
実際に機能しますが、使用されていないにもかかわらず、各テンプレートの特殊化のコードが生成されます。ただし、一般的な定義は生成されません。
これは 1 ステップのコンパイルであり、リンクが続く中間オブジェクト ファイルへのコンパイルではありません。その場合、デッド コードの削除をリンク段階まで延期するのが自然に思えますが、リンカが常にこれを得意としているわけではないことを私は知っています。
誰が何が起こっているのか知っていますか?ここで見逃している微妙なテンプレートの専門化はありますか? 主は、悪魔が C++ の細部に潜んでいることを知っています。
編集: 言及されているため、この動作は -O3 と -Os の両方で発生します。
EDIT2:以下のロブは、関数を匿名の名前空間に配置することを提案しました。そうすることで、任意のレベルの最適化でコンパイルすると、実際にデッド コードが削除されます。これは良いことです。でも気になったので、次のプログラムで同じことをやってみました。
namespace {
void foo() { std::cout << "Foo!" << std::endl; }
void bar() { std::cout << "Bar!" << std::endl; }
}
int
main()
{
foo();
return 0;
}
ここでの考え方は、Rob のソリューションが実際にテンプレートの特殊化に関連しているかどうかを確認することです。結局のところ、最適化をオンにしてコンパイルされた上記のコードはbar()
、実行可能ファイルからの未使用の定義を省略しています。したがって、彼の答えは私の差し迫った問題を解決する一方で、使用されていないテンプレートの特殊化がコンパイルされる理由をまったく説明していないようです。
これを説明する標準からの関連するスニペットを知っている人はいますか? テンプレートは使用時にのみ生成されるといつも思っていましたが、おそらくこれは完全な専門化ではそうではありません...