C++练习
loser homework
实现管道运算符
int main(){
std::vector v{1, 2, 3};
std::function f {[](const int& i) {std::cout << i << ' '; } };
auto f2 = [](int& i) {i *= i; };
v | f2 | f;
}
运行结果
1 4 9
实现
#include <functional>
#include <iostream>
#include <vector>
template <typename t1, typename t2> auto &operator|(t1 &v, t2 &f) {
for (auto &a : v) {
f(a);
}
return v;
}
int main() {
std::vector v{1, 2, 3};
std::function f{[](const int &i) { std::cout << i << ' '; }};
auto f2 = [](int &i) { i *= i; };
v | f2 | f;
}
实现自定义字面量 _f
int main(){
std::cout << "乐 :{} *\n"_f(5);
std::cout << "乐 :{0} {0} *\n"_f(5);
std::cout << "乐 :{:b} *\n"_f(0b01010101);
std::cout << "{:*<10}"_f("卢瑟");
std::cout << '\n';
int n{};
std::cin >> n;
std::cout << "π:{:.{}f}\n"_f(std::numbers::pi_v<double>, n);
}
运行结果
乐 :5 *
乐 :5 5 *
乐 :1010101 *
卢瑟******
6
π:3.141593
实现
这个y1s1,我不太理解,也不能这样说,就是很反直觉,就很感觉很没意义.我直接贴标准答案吧.
constexpr auto operator""_f(const char* fmt, size_t) {
return[=]<typename... T>(T&&... Args) { return std::vformat(fmt, std::make_format_args(std::forward<T>(Args)...)); };
}
这里的“”_f
是自定义字面量,为什么要像(const char* fmt, size_t)
这样写呢?别问,问就是C++11的大手发力了.
这里就是自定义字面量,然后传递lambda,lambda接受参数,然后进行格式化.
实现 print
以及特化 std::formatter
实现一个print
,如果你做了上一个作业,我相信这很简单。 要求调用形式为:
print(格式字符串,任意类型和个数的符合格式字符串要求的参数)
struct Frac {
int a, b;
};
给出自定义类型Frace
,要求支持
Frac f{ 1,10 };
print("{}", f);// 结果为1/10
运行结果
1/10
实现
如果上面只是觉得反直觉,但是能理解的话,这里就更怪了.
template<>
struct std::formatter<Frac>:std::formatter<char>{
auto format(const auto& frac, auto& ctx)const{//const修饰是必须的
return std::format_to(ctx.out(), "{}/{}", frac.a, frac.b);
}
};
void print(std::string_view fmt,auto&&...args){
std::cout << std::vformat(fmt, std::make_format_args(std::forward<decltype(args)>(args)...));
}
就是说vformat
是来识别原本fmt的{}
识别到就把相应参数传入到formatter.format
,而这个通用模板是没有实现任何逻辑了,所以就必须特化(特化居然能继承,长知识了)
这里的继承是为了避免写成员函数parse
,要写也简单,可以这样写:
auto prase(const auto&ctx)const {
return ctx.begin();
}
后续就照着这个写即可.
以后特化,照猫画虎即可.但是我选择用printf
(bushi)
yuesong-feng/30dayMakeCppServer: 30天自制C++服务器,包含教程和源代码
可参考:现代C++并发编程教程