我假设不排除 C++11 解决方案。
我也会假设 OP 认为他希望检测具有签名的函数或函子是正确的bool(int &)
。Dave 建议的使用
std::function
:
void foo(const std::function<bool(int&)>& f);
确实会确保任何可接受的参数f
都包含一个类似一元函数的对象,该对象的参数是可以绑定到的类型,int&
并且其返回类型可以隐式转换为bool
. 但:
double bar(bool b) {
return b ? DBL_MAX : DBL_MIN;
}
就是这样一个对象,将其视为“可调用对象,它接受对 int 的引用并返回 bool”似乎有些牵强。
我们希望测试类类型的函数和对象的事实意味着 SFINAE 类模板在脉络中:
template<typename T>
struct is_predicate_of_ref_to_int_type { ... };
并不完全符合 itelf 的要求,因为虽然我们可以用仿
typename T
函数类型实例化,但我们不能用函数实例化typename T
。
对于一个函数func
,我们应该用T
=实例化decltype(func)
;但是不对称仍然存在,因为对于仿函数类型Functor
,我们不能用T
=实例化decltype(Functor)
,因为Functor
它不是表达式。
一旦我们获得了所讨论对象的类型,这样的 SFINAE 类模板就可以达到目的,但是为了使用统一的习惯用法,我们可以使用重载函数,它的参数同样可以是函数或仿函数对象。这是一个这样的解决方案,附加了一个测试程序:
#include <type_traits>
template<class T>
struct is_predicate_of_ref_to_int_type {
// SFINAE operator-has-correct-sig- :)
template<class A>
static auto test(bool (A::*)(int &)) -> std::true_type;
// SFINAE operator-exists :)
template <class A>
static auto test(decltype(&A::operator()),void *) ->
// So the operator exists. Has it the correct sig?
decltype(test(&A::operator()));
// SFINAE failure :(
template<class A>
static auto test(...) -> std::false_type;
// This will be either `std::true_type` or `std::false_type`
typedef decltype(test<T>(0,0)) type;
static const bool value = type::value;
};
template<typename T>
bool is_predicate_of_ref_to_int(T const & t) {
return is_predicate_of_ref_to_int_type<T>::value;
}
bool is_predicate_of_ref_to_int(bool (function)(int &)) {
return true;
}
// Testing...
struct passing_class_0
{
bool operator()(int & i) {
return i > 0;
}
};
struct failing_class_0
{
bool operator()(int i) {
return i > 0;
}
};
struct failing_class_1
{
bool operator()(int & i, int & j) {
return i > j;
}
}
struct failing_class_2{};
bool passing_function_0(int & i) {
return i > 0;
}
bool failing_function_0(int i) {
return i > 0;
}
int failing_function_1(int & i) {
return i;
}
void failing_function_2(){}
#include <iostream>
using namespace std;
int main()
{
passing_class_0 pc0;
failing_class_0 fc0;
failing_class_1 fc1;
failing_class_2 fc2;
cout << "Expecting pass..." << endl;
cout << is_predicate_of_ref_to_int(pc0) << endl;
cout << is_predicate_of_ref_to_int(passing_function_0) << endl;
cout << "Expecting fail..." << endl;
cout << is_predicate_of_ref_to_int(fc0) << endl;
cout << is_predicate_of_ref_to_int(fc1) << endl;
cout << is_predicate_of_ref_to_int(fc2) << endl;
cout << is_predicate_of_ref_to_int(failing_function_0) << endl;
cout << is_predicate_of_ref_to_int(failing_function_1) << endl;
cout << is_predicate_of_ref_to_int(failing_function_2) << endl;
cout << is_predicate_of_ref_to_int(failing_function_2) << endl;
cout << is_predicate_of_ref_to_int(1L) << endl;
return 0;
}
使用 GCC 4.7.2 或 clang 3.2 构建,具有预期的输出。
有一个警告。任何重载 operator()
的函子类型都将无法通过测试,例如
struct bar
{
bool operator()(int & i) { ... }
bool operator()(int & i, int & j) { ... }
};
即使其中一个重载是令人满意的,由于标准对获取重载成员函数的地址的限制。