14.8関数呼び出し演算子
我々は、オブジェクトの関数として、このようなオブジェクトを呼び出すので、行動の機能のようなオブジェクトを作ることができるオーバーロード関数呼び出し演算子クラス。
通常の関数に対して、関数オブジェクトは、彼のデータの実際のメンバーである状態の一部を保存することができます。
この事実は、順番にとラムダ式として、ラムダ式は、実際のオブジェクトのクラスです。
練習
14.33
ゼロ、1、より多くのことができ、パラメータはデフォルト値を持つことができます
14.34
struct IfThenElse
{
int operator()(int a,int b,int c) {
return a ? b : c;
};
};
14.35
ここでのFunctionオブジェクトは、それが保存され、状態を持つことです
struct ReadString {
ReadString(istream& _is):is(_is){};
string operator()() {
string temp = "";
getline(is, temp);
return temp;
};
istream& is;
};
14.36
ReadString read_string(cin);
string line;
vector<string> vec;
while ((line=read_string())!="") {
vec.push_back(line);
}
ostream_iterator<string> out_iter(cout,",");
std::copy(vec.begin(), vec.end(), out_iter);
14.37
ターゲットは、データメンバーとして書き込むことができます
struct TwoValueEqual
{
bool operator()(const string&str1,const string& target) {
return str1 == target;
};
};
ReadString read_string(cin);
string line;
vector<string> vec;
while ((line = read_string()) != "") {
vec.push_back(line);
}
ostream_iterator<string> out_iter(cout,"\n");
std::copy(vec.begin(), vec.end(), out_iter);
TwoValueEqual func;
auto new_func = std::bind(func, std::placeholders::_1, "123");
//new_func("23");
std::replace_copy_if(vec.begin(), vec.end(), out_iter,new_func,"666");
14.8.1ラムダは、関数オブジェクトであります
ラムダは、ラムダを作成するための匿名クラスの位置が関数オブジェクトを作成し、関数オブジェクトはconstのクラスで、実際には関数オブジェクトです。
ラムダ式は、オーバーロードされた関数呼び出し演算子クラスの宣言に相当します。そして、オーバーロードされた関数は、const型です。
次の2つのステートメントは、基本的に同じです。
struct TwoValueEqual
{
bool operator()(const string&str1,const string& target) {
return str1 == target;
};
};
[](const string&str1,const string& target){
return str1 == target;
};
ラムダ式は、変更可能な変更され、変更する必要があれば、その値は、変更することができないので、ラムダ式、それはオペレータであるため、クラスのデータメンバに対応する、捕捉されたパラメータ値を使用して()関数は、const型です。参照タイプの基準値を用いて捕獲、それを直接変更することができます。
これは、参照型メンバの量は、そのデータ値の関数CONSTを変更することができ、クラスでも可能です。
練習
14.38
struct StringEqualSize
{
StringEqualSize(size_t l, size_t u) :_lower(l), _upper(u) {};
bool operator()(const string&str) const {
return (str.size() >= _lower) && (str.size() <= _upper);
};
size_t _lower;
size_t _upper;
};
--测试代码-
ifstream fin("data.txt");
string word;
map<size_t, size_t>word_count;
vector<StringEqualSize> vec = {
StringEqualSize(1, 1),
StringEqualSize(2, 2),
StringEqualSize(3, 3),
StringEqualSize(4, 4),
};
while (fin>>word) {
for (const auto& item:vec)
{
if (item(word))
{
++word_count[word.size()];
break;
}
}
}
for (const auto& item: word_count)
{
cout << item.first<<" appear "<<item.second<<"times"<< endl;
}
14.39
struct StringEqualSize
{
StringEqualSize(size_t l, size_t u,const string& n) :_lower(l), _upper(u),name(n){};
StringEqualSize(size_t l, bool flag,const string& n) :_lower(l), only_lower(flag),name(n) {};
bool operator()(const string&str) const {
bool flag;
if (only_lower)
{
flag = (str.size() >= _lower);
}
else {
flag= (str.size() >= _lower) && (str.size() <= _upper);
}
return flag;
};
size_t _lower;
bool only_lower;
size_t _upper;
string name;
};
---
ifstream fin("data.txt");
string word;
map<string, size_t>word_count;
vector<StringEqualSize> vec = {
StringEqualSize(1u, 9u,"1~9"),
StringEqualSize(10u, true,">=10")
};
while (fin>>word) {
for (const auto& item:vec)
{
if (item(word))
{
++word_count[item.name];
break;
}
}
}
for (const auto& item: word_count)
{
cout << item.first<<" appear "<<item.second<<"times"<< endl;
}
14.40
わずかに
14.41
あなたは状態関数オブジェクトはクラスを定義する必要がありますと、過去に使用したい場合は、より迅速にラムダ式の使用は、あまり定義せずに、これは非常に面倒になりますので。
いくつかの簡単なロジックのための唯一のラムダ、外の追加のパラメータパラメータ維持する必要性に加えて、あなたはまた、ラムダを使用することができるかもしれ回またはいくつかの小さな機能を表示します。
14.8.2ライブラリ定義は、オブジェクトの機能します
標準ライブラリは、算術演算子、関係演算子、ビット演算子に関数オブジェクトを提供し、これらの関数は、テンプレートオブジェクトです。。
柔軟な標準ライブラリ関数を使用してオブジェクト、アルゴリズム、および機能のアダプタは、私たちの仕事の一部を簡略化することができます。
14.42
A。
vector<int>vec = { 1231,2312,4123,31,32,4321,543,123,132412 };
auto func = std::bind(std::greater<int>(), std::placeholders::_1, 1024);
auto count = std::count_if(vec.begin(), vec.end(), func);
cout << count << endl;
B。
vector<string> vec = { "pooch","pooch","adsf","pooch","12312" };
auto func = std::bind(std::not_equal_to<string>(), std::placeholders::_1, "pooch");
auto iter = std::find_if(vec.begin(), vec.end(), func);
if (iter!=vec.end())
{
cout << *iter << endl;
}
C。
私は、イテレータが同じコンテナにはできませんコピーを使用していたが、コピー元とターゲットは、イテレータイテレータ
vector<int>vec = { 1231,2312,4123,31,32,4321,543,123,132412 };
auto func = std::bind(std::multiplies<int>(), std::placeholders::_1, 2);
std::transform(vec.begin(), vec.end(),vec.begin(),func);
//vector<int> vec;
for (const auto& item:vec) {
cout<<item<<endl;
}
14.43
find_if()は終了()イテレータ返される場合、値がtrue、1割り切れない場合割り切れ即ち0、偽を参照する場合、モジュロを使用するので、その後、シーケンスは、その中のすべての要素で割り切れること。
vector<int>vec = { 2,3,8 };
auto func = std::bind(std::modulus<int>(), 16, std::placeholders::_1);
auto iter = std::find_if(vec.begin(), vec.end(), func);
if (iter==vec.end()) {
cout<<"所有元素都能整除它"<<endl;
}
else {
cout << "有元素不能整除它" << endl;
}
14.8.3呼び出し可能なオブジェクトと機能
()関数では、オーバーロードされた関数ポインタ、ラムダ式、()クラスとstd ::バインド彼らはすべての呼び出し可能オブジェクトです。
これらの呼び出し可能オブジェクトは、独自のタイプを持っていますが、呼び出し可能な異なるタイプのオブジェクトは、コールフォームを共有することができます。
コールの形式と引数の型の戻り値の型で。
すべての呼び出し可能オブジェクト実際には14.44、それらはすべて属し
double(double,double)
フォームを呼び出します。
私たちは、このようなマップを使用して、これらの一元管理が同じ関数を呼び出し形成することができるが、それらは同じタイプではありませんので。
だから、マップの種類の値を決定する方法を、あなたは関数型を使用することができ、この時間は、それは、異なる種類のものであってもよいが、呼び出し可能なオブジェクトの形で同じ呼び出しは同じ型に変換されます。
私は基本的に、包装の層を追加したと思います。
ここでの操作機能のいくつかの特定の種類があります。私たちは、角括弧の形で特定のコールを渡す必要があります。
練習
14.44
double my_minus(double a,double b) {
return a - b;
}
struct my_multi
{
double operator()(double a, double b) {
return a * b;
};
};
struct my_divides
{
double operator()(double a, double b,double c) {
return a / b;
};
};
map<string, std::function<double(double, double)>> caculate;
caculate["+"] = [](double a, double b)->double{return a + b; };
caculate["-"] = my_minus;
caculate["*"] = my_multi();
//caculate["/"] = std::divides<int>();
caculate["/"] = std::bind(my_divides(), std::placeholders::_1, std::placeholders::_2, 0.0);
double a,b;
string oper = "";
while (cin>>a>>oper>>b)
{
cout << a<<oper<<b<<"="<<caculate[oper](a, b) << endl;;
}