SFINAE アプローチを拡張して、クラスに特定のメンバー関数があるかどうかを検出できるかどうか疑問に思っていました (ここで説明したように:
「クラスが特定の署名のメンバー関数を持っているかどうかを知るためのテクニックは C++ にありますか?」 クラスに特定の署名のメンバー関数があるかどうかを確認します
) テンプレート化されたメンバー関数をサポートするには? たとえば、次のクラスで関数 foo を検出できるようにします。
struct some_class {
template < int _n > void foo() { }
};
void foo< 5 >()
次のように、foo の特定のインスタンス化 (たとえば、メンバーかどうかを確認する) に対してこれを行うことが可能であると考えました。
template < typename _class, int _n >
class foo_int_checker {
template < typename _t, void (_t::*)() >
struct sfinae { };
template < typename _t >
static big
test( sfinae< _t, &_t::foo< _n > > * );
template < typename _t >
static small
test( ... );
public:
enum { value = sizeof( test< _class >( 0 ) ) == sizeof( big ) };
};
次に、メンバーがあるfoo_int_checker< some_class, 5 >::value
かどうかを確認します。ただし、MSVC++ 2008 では、これは常に返されますが、g++ では次の構文エラーが行に表示されます。some_class
void foo< 5 >()
false
test( sfinae< _t, &_t::foo< _n > > );
test.cpp:24: error: missing `>' to terminate the template argument list
test.cpp:24: error: template argument 2 is invalid
test.cpp:24: error: expected unqualified-id before '<' token
test.cpp:24: error: expected `,' or `...' before '<' token
test.cpp:24: error: ISO C++ forbids declaration of `parameter' with no type
それ自体がテンプレート パラメーターである型からテンプレート関数のインスタンス化のアドレスを取得しようとしているため、どちらも失敗しているようです。これが可能かどうか、または何らかの理由で標準で許可されていないかどうかを知っている人はいますか?
::template
編集: g++ で上記のコードを正しくコンパイルするための構文を見逃したようです。関数のアドレスを取得するビットを に変更すると&_t::template foo< _n >
、プログラムはコンパイルされますが、MSVC++ と同じ動作になります (value
は常に に設定されfalse
ます)。
のオーバーロードをコメントアウトして、コンパイラに別の...
オーバーロードtest
を強制的に選択させると、g++ で次のコンパイラ エラーが発生します。
test.cpp: In instantiation of `foo_int_checker<A, 5>':
test.cpp:40: instantiated from here
test.cpp:32: error: invalid use of undefined type `class foo_int_checker<A, 5>'
test.cpp:17: error: declaration of `class foo_int_checker<A, 5>'
test.cpp:32: error: enumerator value for `value' not integer constant
ここで、32行目がenum { value = sizeof( test< _class >( 0 ) ) == sizeof( big ) };
行です。残念ながら、これは問題の診断に役立たないようです:(。MSVC ++は同様の説明のないエラーを返します:
error C2770: invalid explicit template argument(s) for 'clarity::meta::big checker<_checked_type>::test(checker<_checked_type>::sfinae<_t,&_t::template foo<5>> *)'
同じ行に。
奇妙なことに、テンプレート パラメーターではなく特定のクラスからアドレスを取得すると (つまり、私が取得するのではなく&_t::template foo< _n >
) &some_class::template foo< _n >
、正しい結果が得られますが、チェッカー クラスは関数に対して単一のクラス ( some_class
) をチェックすることに制限されます。また、次のことを行うと:
template < typename _t, void (_t::*_f)() >
void
f0() { }
template < typename _t >
void
f1() {
f0< _t, &_t::template foo< 5 > >();
}
を呼び出すとf1< some_class >()
、 でコンパイル エラーが発生しません&_t::template foo< 5 >
。これは、SFINAE コンテキスト内で、それ自体がテンプレート パラメーターである型からテンプレート化されたメンバー関数のアドレスを取得する場合にのみ問題が発生することを示唆しています。ああ!