我可以使用SFINAE来检测模板类成员函数吗
Can I use SFINAE to detect template class member functions?
我成功地使用了多次SFINAE。检测类是否提供函数不是问题。我现在的问题似乎和他的问题正好相反!我宁愿只检测类的方法,而不是同时检测派生方法。这似乎与该方法是一个模板这一事实有关。
是否可以检测类模板方法?我试着用一个类型实例化模板,这个类型应该不会有什么害处,但没有成功。
struct A { template<class T> void Func( T ) {}; };
struct B :A {};
template< class T >
struct CheckForFunc
{
typedef char(&YesType)[1];
typedef char(&NoType)[2];
template< class U, void (U::*)( int ) > struct Sfinae;
template< class T2 > static YesType Test( Sfinae<T2,&T2::Func>* );
template< class T2 > static NoType Test( ... );
static const bool value = sizeof(Test<T>(0))==sizeof(YesType);
};
int main(int argc, char* argv[])
{
// gives "1"
std::cout << "Value A=" << CheckForFunc< A >::value << std::endl;
// doesn't compile!
std::cout << "Value B=" << CheckForFunc< B >::value << std::endl;
return 0;
}
错误消息:
error: ‘&A::Func’ is not a valid template argument for type ‘void (B::*)(int)’ because it is of type ‘void (A::*)(int)’
请注意,这个SFINAE与模板方法配合得很好,只是与派生方法不配合!糟糕的是,它不仅检测到错误,而且编译失败。
如何在不使用"sample"类型(此处为int)的情况下编写SFINAE测试?
编辑:对不起,仅限C++03!LLVM也很好,还有VS2008,只是GCC和QNX(我明天必须查看版本)不好。
伊迪丝2:不知道科利鲁!非常酷,这是错误!
这个问题与类模板无关,它得到了正确的解决,而是与成员表达式地址中的一个奇怪的怪癖有关。特别是,具有以下类型:
struct base { void foo(); };
struct derived : base {};
表达式CCD_ 1是类型CCD_。
关于检测成员函数模板存在的测试,我没有答案。你不能获取模板的地址,但你可能会创建一个伪的不可访问类型,并尝试用该类型调用函数。如果函数本身是一个模板,那么类可以拥有采用该类型的函数的唯一方法就是。您可能希望在未求值的表达式中使用此函数,以避免odr在类型中使用模板函数。
我会使用这个修复程序:
Sfinae<T2, decltype(std::declval<T2>().Func(0))>
也就是说,使用表达式obj.Func(0)
的类型并将其传递给Sfinae
类模板。
以下是修复的完整代码:
#include <iostream>
#include <utility>
struct A { template<class T> void Func( T ) {}; };
struct B : A {};
struct C {};
template< class T >
struct CheckForFunc
{
typedef char(&YesType)[1];
typedef char(&NoType)[2];
template< class, class > struct Sfinae;
template< class T2 > static YesType Test( Sfinae<T2, decltype(std::declval<T2>().Func(0))> * );
template< class T2 > static NoType Test( ... );
static const bool value = sizeof(Test<T>(0))==sizeof(YesType);
};
int main(int argc, char* argv[])
{
std::cout << "Value A=" << CheckForFunc< A >::value << std::endl;
std::cout << "Value B=" << CheckForFunc< B >::value << std::endl;
std::cout << "Value C=" << CheckForFunc< C >::value << std::endl;
return 0;
}
输出:
Value A=1
Value B=1
Value C=0
我在这个演示中添加了C
类。
在线演示。:-)
更新到C++20(使用概念)给了我们这个简洁的constexpr解决方案
#include <iostream>
struct A { template<class T> void Func( T ) {}; };
struct B : A {};
struct C {};
template <typename T>
concept CheckForFunc = requires(T t) { t.Func(T()); };
int main(int argc, char* argv[])
{
if constexpr(CheckForFunc<A>) std::cout << "Value A" << std::endl;
if constexpr(CheckForFunc<B>) std::cout << "Value B" << std::endl;
if constexpr(CheckForFunc<C>) std::cout << "Value C" << std::endl;
return 0;
}
输出将是
Value A
Value B
如果您知道成员函数模板应该具有的确切模板参数,这将起作用:(注意,它使用了一些C++11功能,这些功能可以被C++03功能取代)
#include <iostream>
#include <type_traits>
struct A { template<class T> void Func( T ) {} };
struct B :A {};
template< class T >
struct CheckForFunc
{
typedef char(&YesType)[1];
typedef char(&NoType)[2];
template< class T2 > static YesType Test(
typename std::enable_if<
std::is_same<void (T::*)(int), decltype(&T2::template Func<int>)>{},
int
>::type );
template< class T2 > static NoType Test( ... );
static const bool value = sizeof(Test<T>(0))==sizeof(YesType);
};
int main(int argc, char* argv[])
{
// gives "1"
std::cout << "Value A=" << CheckForFunc< A >::value << std::endl;
// doesn't compile!
std::cout << "Value B=" << CheckForFunc< B >::value << std::endl;
return 0;
}
输出:
值A=1
值B=0
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 将公共但非静态的成员函数与ALGLIB集成
- 使用指向成员的指针将成员函数作为参数传递
- 将重载的成员函数传递给函数模板
- 我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
- 如何在C++中使用非静态成员函数作为回调函数
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 关联容器的下界复杂性:成员函数与非成员函数
- 在 C++ 中用派生类型重写成员函数
- 链表的泛型函数remove()与成员函数remove)
- 如何将lambda作为模板类的成员函数参数
- constexpr构造函数需要常量成员函数时出现问题
- 将自由函数绑定为类成员函数
- 区分非成员函数和头文件中的成员函数
- 如何从子成员函数修改父公共成员变量
- 保留对其他类的成员函数的引用
- 在运算符重载定义中使用成员函数(const错误)
- 内联如何影响模块接口中的成员函数
- 将成员函数指针作为参数传递给模板方法