C++ 小技巧
输出变量名、行号、值
#define dbg(x) (cout << __LINE__ << ": " << #x << "=" << x << endl)
#x会被编译器替换为变量x的名称,是一个字符串__LINE__表示当前代码行__file__表示文件名
实现元组解构、多值返回
通过tuple<...>实现
元组解构
int main() {
int x;
string y;
tie(x, y) = make_tuple(5, "OK"); // tuple
dbg(x);
dbg(y);
}
多值返回
auto f() {
return make_tuple(5, "OK");
}
int main() {
int x;
string y;
tie(x, y) = f();
dbg(x);
dbg(y);
}
实现Kotlin中的Result
C语言的union
union testUnion {
int value;
bool error;
};
int main() {
union testUnion r;
r.value = 5;
dbg(r.error); //未定义行为,根据内存模型应该是true
}
在C++中,用std::variant来实现更好的union
int main() {
variant v;
v = "Hello";
dbg(get(v));
// dbg(get(v)); // 抛出bad_variant_access异常
v = 5;
dbg(get(v));
}
所以Reslut相当于variant
但是有个头疼的问题:如何判断是T还是E
同kotlin一样,C++有会引发exception的std::get和返回null的std::get_if
如果想像Kotlin那样用fold得自己封装,可以参考std::visit
int main() {
variant v;
struct {
void operator()(int) {
std::cout << "int!\n";
}
void operator()(std::string const&) {
std::cout << "string!\n";
}
} visitor;
visit(visitor, v);
}
当然,这段代码不够"现代",这是一个更现代的版本:
int main() {
variant v = "OK";
auto visitor = [](auto& value) {
if constexpr (is_convertible()) { //判断为string类型
cout << "String: " << value << endl;
}
else if constexpr (is_convertible()) { //判断为int类型
cout << "Int: " << value << endl;
}
};
visit(visitor, v);
}
他们是等价的,这样说明了匿名函数实际上就是重载operator()的struct
"魔法"
//摘自 CppReference,详细解析可以看@zwvista的博文: https://www.cnblogs.com/zwvista/p/9256655.html
template struct overloaded : Ts... { using Ts::operator()...; }; //将多个类(Ts...)的operator()通过继承合并到一个类中
template overloaded(Ts...)->overloaded; // 自动推断向导,帮助编译器根据 overloaded 构造器参数的类型来推导 overloaded 的模板参数类型
int main() {
std::variant var;
std::visit(overloaded{
[](auto arg) { std::cout << arg << ' '; },
[](double arg) { std::cout << std::fixed << arg << ' '; },
[](const std::string& arg) { std::cout << arg << ' '; },
}, var);
}
这个堪称完美,建议出个std::overloaded(逃