VC9 のヘッダーファイルを参考にしてライブラリを開発しています。
以下のように VC9 のヘッダーにはテンプレート関数の定義で
__cdecl がある関数と __cdecl がない関数がありました。
std::advance() の定義
template<class _InIt, class _Diff>
inline void __cdecl advance(_InIt& _Where, _Diff _Off) { ... }
std::find() の定義
template<class _InIt, class _Ty>
inline _InIt find(_InIt _First, _InIt _Last, const _Ty& _Val) { ... }
非テンプレート関数の場合は __cdecl のような呼び出し規約を明示しないと
ライブラリのユーザーが /Gz などのオプションでコンパイルしたときに
リンクエラーが出るので __cdecl は省略できないと思いますが、
テンプレート関数の場合は __cdecl のありなしをどのように分けているの
でしょうか?
関数テンプレートの場合
・当該関数テンプレートの詳細がコンパイル時点で明確になっている必要がある
・関数テンプレートの実体化は各翻訳単位で行われる(弱実体化)
・VC++ の実装上関数呼び出し規約がマングル名の中に含まれる
・弱実体化と強実体化が重複していると弱実体化で作られた実体は捨てられる
ということから、「関数テンプレートを実体化する場合」に限って言うならば
リンクエラーはまず出ない(原理的にでるわけが無い)
なので __cdecl だろうがそうでなかろうが「最終生成物で、当該関数が実行できる」
という1点を取れば大差ない。
fstream や string など template で実装されているが、実用上よく使うのは
型が固定されているものに限定されている
という奴については DLL 内部に強実体を持っている/持たせているものがあり
そういうのを使う場合には適切に __cdecl 等を指定することで省メモリになる
可能性がある、かもしれないな
tetrapod 様ありがとうございました。
コードサイズ以外は __cdecl の有無でそれほど違いが出ないということですね。
ルールを単純にするためテンプレートかどうかにかかわらず __cdecl を指定する
ことにしました。また関数へのポインタの型も __cdecl に固定されるので混乱が
少なくなるかもしれません。