5

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_classvoid foo< 5 >()falsetest( 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 コンテキスト内で、それ自体がテンプレート パラメーターである型からテンプレート化されたメンバー関数のアドレスを取得する場合にのみ問題が発生することを示唆しています。ああ!

4

1 に答える 1

1

Boost.MPL には、「BOOST_MPL_HAS_XXX_TRAIT_DEF」と呼ばれる同様のものが既に実装されています。見る:

http://www.boost.org/doc/libs/1_41_0/libs/mpl/doc/refmanual/has-xxx-trait-def.html

クラスに特定の名前付きtypeがあるかどうかを検出できます。

また、特定のケースでは、関数ポインターをパラメーター (void (_t::*)()) として渡す代わりに、メソッドの本体で使用してみてください。つまり、次のようにします。

template < typename _t >
static big test( sfinae<_t> )
{
  &_t::foo<_n>;
}
于 2010-01-25T15:26:47.790 に答える