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 への参照を取り、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) { ... }
};
オーバーロードされたメンバー関数のアドレスを取得する際の標準の制限により、オーバーロードの 1 つが満足できるものであっても。