确定仿函数的参数和结果类型

时间:2012-06-13 12:07:35

标签: c++ functor sfinae

如何测试仿函数是否是一个可调用的对象,它引用一个int并返回一个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;
    }
};

3 个答案:

答案 0 :(得分:1)

在我看来,你真的不想检查一个仿函数的签名,你想要限制用户可以传入的内容,首先:

如果您有权访问std::function,则可以执行此操作:

void foo(const std::function<bool(int&)>& f)

答案 1 :(得分: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 { ... };
虽然我们可以实例化,但

不太适合自己的法案 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) { ... }
};

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

答案 2 :(得分:0)

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