我有一个类,它重载了多种输入类型的 (( 运算符,即
struct Type {
void operator()(int);
void operator()(std::string);
};
现在,我想使用 SFINAE 来检查是否存在 (( 运算符的特定重载,即
if (Type()(std::string) overload exists) {
// do something...
}
这在 C++11 中可以做到吗?(我不能使用 C++14 或 C++17(。
注意:在实际代码中,有一个模板类接受具有某些属性的类类型。此模板中有一个成员函数,该函数将根据参数类型的 (( 运算符的某些特定重载是否存在进行专用。
使用 SFINAE 检查是否可以将指向要查找的operator()
重载的成员进行指针。
以下是我将如何做到这一点:
#include <type_traits>
template <typename A, typename B, typename = void>
struct has_overload : std::false_type {};
template <typename A, typename B>
struct has_overload<A, B, decltype((void)(void (A::*)(B))&A::operator())> : std::true_type {};
用法: has_overload<Type, std::string>::value
.
第一步,我将Type::opeator()
限制为仅采用特定类型,即 int
和string
.
struct Type {
void operator()(int) {}
void operator()(std::string) {}
template<class U>
void operator()(U) = delete;
};
通过这种方式,我们禁用隐式转换。
然后我们可以编写这样的类模板:
template<class T, class = void>
struct canInvokeFor : std::false_type {};
template<class Arg>
struct canInvokeFor< Arg, decltype ( std::declval<Type>().operator ()(Arg{}) ) >
: std::true_type {};
在其专业化中,我们模拟为传递的Arg
类型调用operator()
。结果:
struct Foo {};
std::cout << canInvokeFor<int>::value << std::endl; // 1
std::cout << canInvokeFor<std::string>::value << std::endl; // 1
std::cout << canInvokeFor<float>::value << std::endl; // 0
std::cout << canInvokeFor<char>::value << std::endl; // 0
std::cout << canInvokeFor<Foo>::value << std::endl; // 0
在 c++11 下演示