Chapter I Lambda in C++98/03
1. Lambdas in C++98/03
Last Modified: 28 August 2024
本章的主要内容
- How to pass the functor to algorithms in the standard library
- Limit of functions and function pointer (funaction pointer)
- Why isn't the function aids good enough?
在 C++98/03 中的可调用对象(callable object)
In the design concept of the C++ standard library, algorithms such as "std::sort", "std::for_each", "std:transform" can accept any callable object (callable objects) and apply it to input into the packaging, however, in the C++98/03 standard, these algorithms can only accept functional pointers and imitations (functional objects).
Use a function here to output the element in vector.
General realization:
#include <algorithm>
#include <iostream>
#include <vector>
void PrintFunc(int x){
std::cout << x << '\n';
}
int main(){
std::vector<int> v;
v.push_back(1);
v.push_back(2);
for_each(v.begin(), v.end(), PrintFunc);
}
/* output:
* 1
* 2
*/
C++The code above is std: :for_each runs through the vector container (for reasons C++98/03 is not supported), and it transfers PrintFunc as a callable object.
Convert this function to a analogue function (functor):
#include <iostream>
#include <vector>
#include <algorithm>
struct PrintFunctor{
void operator()(int x) const {
std::cout << x << '\n';
}
};
/* or this version
class PrintFunctor{
public:
void operator()(int x) const {
std::cout << x << '\n';
}
};
*/
int main(){
std::vector<int> v;
v.push_back(1);
v.push_back(2);
for_each(v.begin(), v.end(), PrintFunctor());
}
/* output:
* 1
* 2
*/
C++The above example uses an imitation function with an optator(s).
Function pointers, however, are usually non-state, i.e. they point to only one function and do not store any additional information or state, as compared to imitations, which allow them to store between multiple calls.
Defines a simple imitation function that records the number of times it is called. The key is to define the state in the imitation function:
#include <algorithm>
#include <iostream>
#include <vector>
class printFunctor{
public:
printFunctor(const std::string str): strText(str), numCalls(0) { }
void operator()(int x){
std::cout << strText << x << '\n';
}
int getNumCalls() const{
return numCalls;
}
private:
std::string strText;
mutable int numCalls;
};
int main(){
std::vector v = {1, 2, 3, 4, 5, 6};
std::string preText = "Elem: ";
printFunctor visitor =
std::for_each(v.begin(), v.end(), printFunctor(preText));
std::cout << "numCalls: " << visitor.getNumCalls() << '\n';
}
/* output:
* 1
* 2
* 3
* 4
* 5
* 6
* numCalls: 6
*/
C++仿函数(functor)的问题
While a separate class can be used to design a function, it is difficult to read and maintain a function at a different location from the algorithm, which results in the function code being located far away from the algorithm to be used in the source file.
In C++98/03, one limitation is that local types (types defined within functions) cannot be used as template parameters, such as:
int main(){
/* define a type inside a function */
struct PrintFunctor{
void operator()(int x) const{
std::cout << x << '\n';
}
};
std::vector<int> v(10, 1);
std::for_each(v.begin(), v.end(), PrintFunctor());
}
C++The following errors can be made using the -std=C++98 standard of the GCC:
error: template argument for
'template<class _IIter, class _Funct> _Funct
std::for_each(_IIter, _IIter, _Funct)'
uses local type 'main()::PrintFunctor'
C++使用 辅助函数(functional helper) 解决
In Standard Library <functional>
Headers, many types and functions can be used with standard algorithms:std::plus<T>()
: Accept two parameters and return them together.std::minus<T>()
: Accept two parameters and return their differences.
#include <functional>
#include <iostream>
#include <vector>
#include <algorithm>
int main(){
std::vector<int> vi1 = {1, 2, 3, 4, 5, 6};
std::vector<int> vi2 = {2, 3, 4, 5, 6, 7};
std::vector<int> vRes(vi1.size());
std::transform(vi1.begin(), vi1.end(), vi2.begin(),
vRes.begin(), std::plus<int>());
std::cout << "Res for plus: ";
for(int n: vRes) std::cout << n << ' ';
std::transform(vi1.begin(), vi1.end(), vi2.begin(),
vRes.begin(), std::minus<int>());
std::cout << "\nRes for minus: ";
for(int n: vRes) std::cout << n << ' ';
}
/* output:
* Res for plus: 3 5 7 9 11 13
* Res for minus: -1 -1 -1 -1 -1 -1
*/
C++std::less<T>()
: Accepts two parameters and returns if the first parameter is smaller than the second.std::greater_equal<T>()
: Accepts two parameters and returns whether the first parameter is greater than or equal to the second parameter.std::bind1st
: Creates a callable object that fixes the first parameter to a given value.std::bind2nd
: Creates a callable object and fixes the second parameter to a given value.
Benefits of using auxiliary functions:
#include <algorithm>
#include <functional>
#include <vector>
int main(){
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
const size_t smaller5 = std::count_if(
v.begin(), v.end(),
std::bind2nd(std::less<int>(), 5));
return smaller5;
}
C++In the code above, use std::bind2nd to bind 5 to the second parameter (x < 5) of the std::less function (x < y), which returns the value return x < 5.
const size_t greater5 = std::count_if(
v.begin(), v.end(),
std::bind1st(std::less<int>(), 5));
C++Similarly, using std::bind1st bound 5 to the first parameter (5 y), returns the value return 5 < x.
Supplement: use of std:bind
#include <iostream>
#include <functional>
int add(int x, int y){
std::cout << "1st param: " << x << '\n';
return x + y;
}
int main(){
/* 创建一个绑定第一个参数为10的函数对象 */
auto res = std::bind(add, 10, std::placeholders::_1);
std::cout << "12 + 10 = " << res(12) << '\n';
}
/* output:
* 12 + 10 = 1st param: 10
* 22
*/
C++In many cases, however, a function is achieved with a number of functions, and the syntax here is complicated:
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
const size_t val = std::count_if(v.begin(), v.end(),
std::bind(std::logical_and<bool>(),
std::bind(std::greater<int>(), _1, 2),
std::bind(std::less_equal<int>(), _1, 6)));
C++The result of the above complex syntax is a return x > 2 & x < = 6.
These issues have improved in the C++ 11 that follows.