C++
呼び出し可能オブジェクト
サーチ…
前書き
呼び出し可能オブジェクトは、関数として使用できるすべてのC ++構造体の集合体です。実際には、これはC ++のSTL関数invoke()に渡すことも、std :: functionのコンストラクタで使うこともできるすべてのものです。関数ポインタ、operator()を持つクラス、暗黙のクラス変換、関数への参照、メンバ関数へのポインタ、メンバデータへのポインタ、lambda。呼び出し可能オブジェクトは、多くのSTLアルゴリズムで述語として使用されます。
備考
Stephan T. Lavavej( <機能>:新機能、適切な使い方 )( スライド )の非常に便利な話は、このドキュメントの基礎につながります。
関数ポインタ
関数ポインタは関数を渡す最も基本的な方法であり、Cでも使用できます(詳細はCのドキュメントを参照してください)。
呼び出し可能オブジェクトの目的のために、関数ポインタは以下のように定義することができます。
typedef returnType(*name)(arguments); // All
using name = returnType(*)(arguments); // <= C++11
using name = std::add_pointer<returnType(arguments)>::type; // <= C++11
using name = std::add_pointer_t<returnType(arguments)>; // <= C++14
独自のベクトルソートを記述するために関数ポインタを使用すると、次のようになります。
using LessThanFunctionPtr = std::add_pointer_t<bool(int, int)>;
void sortVectorInt(std::vector<int>&v, LessThanFunctionPtr lessThan) {
if (v.size() < 2)
return;
if (v.size() == 2) {
if (!lessThan(v.front(), v.back())) // Invoke the function pointer
std::swap(v.front(), v.back());
return;
}
std::sort(v, lessThan);
}
bool lessThanInt(int lhs, int rhs) { return lhs < rhs; }
sortVectorInt(vectorOfInt, lessThanInt); // Passes the pointer to a free function
struct GreaterThanInt {
static bool cmp(int lhs, int rhs) { return lhs > rhs; }
};
sortVectorInt(vectorOfInt, &GreaterThanInt::cmp); // Passes the pointer to a static member function
あるいは、次のいずれかの方法で関数ポインタを呼び出すことができます。
-
(*lessThan)(v.front(), v.back()) // All
-
std::invoke(lessThan, v.front(), v.back()) // <= C++17
operator()を持つクラス(Functor)
operator()
をオーバーロードするすべてのクラスを関数オブジェクトとして使用できます。これらのクラスは手作業で記述することができます(しばしばファンクタと呼ばれます)。あるいはC ++ 11からLambdasを書くことによってコンパイラによって自動的に生成されます。
struct Person {
std::string name;
unsigned int age;
};
// Functor which find a person by name
struct FindPersonByName {
FindPersonByName(const std::string &name) : _name(name) {}
// Overloaded method which will get called
bool operator()(const Person &person) const {
return person.name == _name;
}
private:
std::string _name;
};
std::vector<Person> v; // Assume this contains data
std::vector<Person>::iterator iFind =
std::find_if(v.begin(), v.end(), FindPersonByName("Foobar"));
// ...
ファンクタは独自のアイデンティティーを持っているため、typedefに入れることはできず、テンプレート引数を使用して受け入れる必要があります。 std::find_if
の定義は次のようになります。
template<typename Iterator, typename Predicate>
Iterator find_if(Iterator begin, Iterator end, Predicate &predicate) {
for (Iterator i = begin, i != end, ++i)
if (predicate(*i))
return i;
return end;
}
C ++ 17以降では、述語の呼び出しはinvoke: std::invoke(predicate, *i)
で行うことができます。