C++ 20 也已经了解一段时间了。自己的感觉是:大佬们在推函数式编程和模板元编程。本来自己是 Java 出身,想深入OOP。但是,现在看来,有必要深入了解一下函数式和模板元编程了。先从函数式编程开始。《C++ 函数式编程》正好香雪馆有这本书,近水楼台,就不买了!
函数式编程
命令式实现统计多个文件的行数
std::vector<int>
count_lines_in_files_command(const std::vector<std::string>& files)
{
std::vector<int> results;
char c = 0;
for (const auto& file : files) {
int line_count = 0;
std::ifstream in(file);
while (in.get(c))
{
if (c == '\n')
{
line_count++;
}
}
results.push_back(line_count);
}
return results;
}
声明式实现统计多个文件的行数
int count_lines(const std::string& filename)
{
std::ifstream in(filename);
in.unsetf(std::ios_base::skipws);
return (int) std::count(
std::istream_iterator<char>(in),
std::istream_iterator<char>(),
'\n');
}
std::vector<int>
count_lines_in_files(const std::vector<std::string>& files)
{
std::vector<int> results;
for (const auto& file : files) {
results.push_back(count_lines(file));
}
return results;
}
上述声明式实现的优势
函数式编程的主要思想
使用 std::transform 进一步抽象
std::vector<int>
count_lines_in_files_transform(const std::vector<std::string>& files)
{
std::vector<int> results(files.size());
std::transform(files.cbegin(), files.cend(),
results.begin(),
count_lines);
return results;
}
通过 range 和 range transformations 再次抽象
std::vector<int>
count_lines_in_files_range(const std::vector<std::string>& files)
{
//使用 | 管道操作符表示通过 transform 传递一个集合
auto view = files | std::views::transform(count_lines) ;
return { std::ranges::begin(view), std::ranges::end(view) };;
}
(T -> bool)
作为参数,并返回一个过滤后的集合filter: (collection, (T -> bool)) -> cllection
transform: (collection, (In -> Out)) -> collection
std::accumulate()
std::reduce()
std::multiplies<>()
作为最后一个参数将算法改为求乘积auto average_score(const std::vector<int>& scores) -> double
{
return std::accumulate(
scores.cbegin(), scores.cend(),
0
) / (double)scores.size();
}
auto average_score(const std::vector<int>& scores) -> double
{
return std::reduce(
std::execution::par,
scores.cbegin(), scores.cend(),
0
) / (double)scores.size();
}
auto product_score(const std::vector<int>& scores) -> double
{
return std::accumulate(
scores.cbegin(), scores.cend(),
1,
std::multiplies<int>()
);
}
std::accumulate()
是折叠的一种实现f: (R, T) -> R
f
f
.f
最后一次调用的返回值crbegin 和 crend
std::find_if()
auto trim_left(std::string s) -> std::string
{
s.erase(
s.begin(),
std::find_if(s.begin(), s.end(), is_not_space)
);
return s;
}
auto trim_right(std::string s) -> std::string
{
s.erase(
std::find_if(s.rbegin(), s.rend(), is_not_space).base(),
s.end()
);
return s;
}
auto trim(std::string s) -> std::string
{
return trim_left(trim_right(std::move(s)));
}
std::partition()
和 std::stable_partition()
std::stable_partition()
可以保持集合中原来的顺序std::remove_if()
和 std::remove()
erase()
,由它来执行people.erase(
std::remove_if(people.begin(), people.end(),
is_not_female),
people.end());
std::copy_if()
std::back_inserter()
包裹目标集合即可std::copy_if(people.cbegin(), people.cend(),
std::back_inserter(females),
is_female);
std::transform()
转换函数
std::transform(females.cbegin(), females.cend(),
names.begin(),
name);
int max(int arg) {...}
auto max(int arg) -> int {...}
int answer = 1;
auto ask() { return answer; }
const auto& ask() { return answer; }
decltype(auto)
作为返回值类型
decltype(auto) ask() { return answer; }
template <typename Object, typename Function>
decltype(auto) call_on_object(Object&& object, Function func)
{
return func(std::forward<Object>(object));
}
&&
std::forward
原样传递参数auto ask() -> int { return 1; }
using function_ptr = decltype(ask)*;
class convertible_to_function_ptr
{
public:
operator function_ptr() const
{
return ask;
}
};
auto ask_ptr = &ask; //函数指针
std::cout << ask_ptr() << std::endl;
auto& ask_ref = ask; //函数引用
std::cout << ask_ref() << std::endl;
convertible_to_function_ptr ask_weapper; //可以自动转换成函数指针的对象
std::cout << ask_weapper() << std::endl;
class function_object
{
public:
return_type operator()(arguments) const
{
...
}
};
//创建一个有内部状态的函数对象类
class older_than {
public:
older_than(int limit)
: m_limit(limit)
{
}
bool operator() (const person_t &person) const
{
return person.arg() > m_limit;
}
private:
int m_limit;
};
...
//这样可以创建不同状态的对象实例
older_than older_than_2(2);
older_than_2(person);
class older_than {
public:
older_than(int limit)
: m_limit(limit)
{
}
template <typename T>
bool operator() (T &&object) const
{
return std::forward<T>(object).age() > m_limit;
}
private:
int m_limit;
};
...
older_than predicate(1);
//函数对象可以作为谓词传递给算法
std::count_if(persons.cbegin(), persons.cend(), predicate);
[a, &b](int x, int y) { return a*x + b*y; }
[a, &b]
指明了包含 lambda 的范围的哪些变量在体中可见[=]
[&]
[this]
[=, &a]
[&, a]
std::count_if(
m_employees.cbegin(), m_employees.cend(),
[this, &team_name]
(const person_t &employee)
{
return team_name_for(employee) == team_name;
}
);
[session = std::move(sessiont), time = current_time()]
auto predicate = [limit = 42](auto&& object)
{
return object.age() > limit;
}
[] (auto first, decltype(first) second) {...}
[] (T first, T scend) {...}
class error_test_t
{
public:
error_test_t(bool error = true)
: error_{ error }
{
}
template<typename T>
auto operator()(T&& value) const -> bool
{
return error_ == (bool)std::forward<T>(value).error();
}
error_test_t operator==(bool test) const
{
//如果 test 为 true,就返回谓词当前的状态
//如果为 false , 就返回状态的逆状态
return error_test_t(test ? error_ : !error_);
}
error_test_t operator!() const
{
//返回当前谓词的逆状态
return error_test_t(!error_);
}
private:
bool error_;
};
error_test_t error(true);
error_test_t not_error(false);
ok_responses = filter(responses, not_error);
ok_responses = filter(responses, !error);
ok_responses = filter(responses, error == false);
failed_responses = filter(responses, error);
failed_responses = filter(responses, error == true);
failed_responses = filter(responses, not_error == false);
std::greater<>()
, 而不用写作 std::greater()
std::function test_function;
test_function = std::fmaxf; //普通函数
test_function = std::multiplies(); //含有调用操作符的类
test_function = std::multiplies<>(); //包含通用调用操作符的类
test_function = [x](float a, float b) { return a*x + b; }; // lambda 表达式
test_function = [x](auto a, auto b) { return a*x + b; }; //通用 lambda