如何确定一个类是否具有特定的模板化成员函数?

Aoz*_*ine 5 c++ sfinae

我想知道是否有可能扩展SFINAE方法来检测一个类是否具有某个成员函数(如下所述:

"在C++中是否有一种技术可以知道一个类是否具有给定签名的成员函数?" 检查类是否具有给定签名的成员函数

)支持模板化成员函数?例如,为了能够检测以下类中的函数foo:

struct some_class {
   template < int _n > void foo() { }
};
Run Code Online (Sandbox Code Playgroud)

我认为有可能为foo的特定实例化做这个(例如检查是否void foo< 5 >()是成员),如下所示:

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 ) };

};
Run Code Online (Sandbox Code Playgroud)

然后foo_int_checker< some_class, 5 >::value检查是否some_class有会员void foo< 5 >().但是在MSVC++ 2008上,这总是返回,false而g ++在该行提供以下语法错误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
Run Code Online (Sandbox Code Playgroud)

两者似乎都失败了,因为我试图从一个本身就是模板参数的类型中获取模板函数实例化的地址.有谁知道这是否可能,或者由于某些原因它是否被标准禁止?

编辑:似乎我错过了使用::templateg ++正确编译上述代码的语法.如果我改变了我获得函数地址的位,&_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
Run Code Online (Sandbox Code Playgroud)

where line 32 is the enum { value = sizeof( test< _class >( 0 ) ) == sizeof( big ) }; line. Unfortunately this doesn't seem to help me diagnose the problem :(. MSVC++ gives a similar nondescript error:

error C2770: invalid explicit template argument(s) for 'clarity::meta::big checker<_checked_type>::test(checker<_checked_type>::sfinae<_t,&_t::template foo<5>> *)'
Run Code Online (Sandbox Code Playgroud)

on the same line.

What's strange is that if I get the address from a specific class and not a template parameter (i.e. rather than &_t::template foo< _n > I do &some_class::template foo< _n >) then I get the correct result, but then my checker class is limited to checking a single class (some_class) for the function. Also, if I do the following:

template < typename _t, void (_t::*_f)() >
void
f0() { }

template < typename _t >
void
f1() {
  f0< _t, &_t::template foo< 5 > >();
}
Run Code Online (Sandbox Code Playgroud)

and call f1< some_class >() then I DON'T get a compile error on &_t::template foo< 5 >. This suggests that the problem only arises when getting the address of a templated member function from a type that is itself a template parameter while in a SFINAE context. Argh!

e.t*_*deu 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

它可以检测类是否具有给定的命名类型

另外,对于您的具体情况,不要将函数指针作为参数传递(void (_t::*)()),而是尝试在方法主体中使用它,即:

template < typename _t >
static big test( sfinae<_t> )
{
  &_t::foo<_n>;
}
Run Code Online (Sandbox Code Playgroud)