まず、コンパイル時に決定を下す必要があります。そうしないと、ブランチにアクセスしたことがない場合でも、関数を提供する必要があります。私は次のようなものを想像することができます:
template <typename T, void (T::*)() > struct HasBar;
template <typename T>
void doBar( HasBar<&T::bar>* ) { T::bar(); }
template <typename T>
void doBar( ... ) {}
template <typename T>
class X
{
static void f()
{
doBar<T>( 0 );
}
};
それは多かれ少なかれ古典的なトリックです。失敗した場合&T::bar
(Tにメンバーバーがないため)、doBar(
HasBar<...>)
失敗のインスタンス化では、関数はオーバーロードセットに追加されないため、もう1つが呼び出されます。が正当な式である場合&T::bar
、両方の関数テンプレートを正常にインスタンス化でき、との0
一致の前にポインターへの変換が選択されます...
(これは、関数のオーバーロード解決を決定する際の最後の手段です)。
編集:
関数が静的であるという事実を見逃しました。上記は非静的関数の場合です。静的関数の場合、最初の行を次のように変更します。
template <typename T, void (*)() struct HasBar;
残りはそのまま動作するはずです。