4

How can I test whether functor is a callable object which takes a reference to an int and returns a bool?

template<typename functor>
void foo(functor f)
{
    static_assert('functor == bool (int&)', "error message");

    int x = -1;
    if (f(x))
        std::cout << x << std::endl;
}

bool bar(int& x)
{
    x = 4711;
    return true;
}

struct other
{
    bool operator()(int& x)
    {
        x = 815;
        return true;
    }
};
4

3 回答 3

1

在我看来,您并不想检查函子的签名,而是首先要限制用户可以传入的内容:

如果您有权访问,std::function您可以这样做:

void foo(const std::function<bool(int&)>& f)
于 2012-06-13T12:43:12.437 回答
1

我假设不排除 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) { ... }
};

即使其中一个重载是令人满意的,由于标准对获取重载成员函数的地址的限制。

于 2013-04-27T17:22:33.273 回答
0

如果您的编译器支持它,您可以使用标头<type_traits>is_function.

于 2012-06-13T12:15:38.837 回答