2012-06-13 28 views
4

如何測試函子是否是一個可調用的對象,它接受對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; 
    } 
}; 
+1

您是否有可用的C++ 11編譯器?你可以使用boost類型特徵庫嗎? –

+1

你想區分'other :: operator()'和'bar()'嗎?或者你只是想知道'functor f'是否是'bool(int&)'類型? – iammilind

+0

你的意思是這樣的:http://ideone.com/22Llh(從維基百科複製和破解)? – Vlad

回答

0

如果你的編譯器支持它,你可以使用頭<type_traits>is_function

1

看起來像你對我真的不希望確認的函子的簽名,你要限制哪些用戶可以傳遞,擺在首位:

如果你有std::function訪問可以這樣做:

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

我假定不排除C++ 11解決方案。

我也會假設OP是正確的,相信他希望 檢測到具有簽名bool(int &)的函數或函子。使用 std::function,如由Dave建議:

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

將確實確保作爲f可接受任何參數包含 一元函數狀對象,其參數是一個類型的那 可以結合int&並且其返回類型可隱式轉換爲 至bool。但是:

double bar(bool b) { 
    return b ? DBL_MAX : DBL_MIN; 
} 

是這樣一個對象,它似乎牽強估計它是「可調用對象 將參考爲int並返回一個布爾值。」

,我們希望測試函數和類的對象 意味着在靜脈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或鐺3.2,這具有預期的輸出。

有一個警告。過載operator()的任何函子類型將失敗 測試,例如,

struct bar 
{ 
    bool operator()(int & i) { ... } 
    bool operator()(int & i, int & j) { ... } 
}; 

即使重載之一是令人滿意的,由於在服用重載成員函數的地址的標準的 限制。