C++17 变长参数模板

任意个数、任意类别的模板参数 template<typename... Ts> class Magic; // 计算参数的个数 template<typename... Ts> void magic(Ts... args) { std::cout << sizeof...(args) << std::endl; } 递归解包: C++17 之前 template<typename T0> void my_printf(T0 value) { std::cout << value << std::endl; } template<typename T, typename... Ts> void my_printf(T value, Ts... args) { std::cout << value << std::endl; my_printf(args...); } int main() { my_printf(1, 2.2, "abc", 'a'); return 0; } C++17 变参模板展开: template<typename T, typename....

April 13, 2022 · 1 min · Rick Cui

C++17 使用结构化绑定来解包绑定的返回值

注意:使用结构化绑定时,就不能再使用 std::tie 创建虚拟变量了,所以我们不得不绑定所有值到命名过的变量上。对部分成员进行绑定的做法是高效的,因为编译器可以很容易的对未绑定的变量进行优化 std::pair<int,int> divide_remainder(int dividend, int divisor){ int f = dividend / divisor; int s = dividend % divisor; return {f, s}; } int main() { auto [dividend, remainder] = divide_remainder(16, 3); std::cout << "16 / 3 is " << dividend << " with a remainder of " << remainder << '\n'; // 之前的写法 int remainder1; std::tie(std::ignore, remainder1) = divide_remainder(16, 5); std::cout << "16 % 5 is " << remainder1 << '\n'; return 0; }

April 12, 2022 · 1 min · Rick Cui

C++17 大括号初始化

( expression-list ):优先调用非聚合初始化,且会存在隐式转换 = expression: { initializer-list }:如果有聚合初始化(initializer_list<>),就调用聚合初始化,没有的话就调用符合条件的非聚合初始化 = { initializer-list }:同上 使用 auto 声明的变量括号初始化,只允许一个参数的情况 {} 与 () 调用构造函数初始化的方式,不同点在于 {} 没有类型的隐式转换,比如 int x(1.2); 和 int x = 1.2; 通过隐式的对浮点值进行向下取整,然后将其转换为整型,从而将 x 的值初始化为 1。相反的, int x{1.2}; 将会遇到编译错误,初始化列表中的初始值,需要与变量声明的类型完全匹配。 测试代码一: // #define AGGREGATE_INIT class Test{ public: Test(int a, float b, char* c){ cout << "int float char* initialize..." << endl; } Test(int a, int b, int c){ cout << "int int int initialize....

April 12, 2022 · 2 min · Rick Cui

C++17 constexpr-if 简化编译

它能处理不同模板类型的特化,因为它可以在完全不同的代码中,选取相应的片段,依据这些片段的类型对模板进行特化 比如我们有一个简单的类,它的成员函数 add ,支持对 U 类型值与 T 类型值的加法 template <typename T> class addable { T val; public: addable(T v) : val{v} {} template <typename U> T add(U x) const { return val + x; } }; 假设类型 T 是 std::vector<something> ,而类型 U 是 int。这里就有问题了,为整个 vector 添加整数是为 了什么呢?应该是对 vector 中的每个元素加上一个整型数。实现这个功能就需要在循环中进行 template <typename U> T add(U x) { auto copy (val); // Get a copy of the vector member for (auto &n : copy) { n += x; } return copy; } 把两种情况结合在一起:...

April 12, 2022 · 2 min · Rick Cui

const_cast

函数指针和成员函数指针无法用于 const_cast const_cast 使得指向非 const 类型的 const 引用或指针能够被修改 通过 const_cast 修改 const 对象是未定义的行为 struct type { int i; type(): i(3) {} void f(int v) const { // this->i = v; // compile error: this is a pointer to const const_cast<type*>(this)->i = v; // OK as long as the type object isn't const } }; int main() { int i = 3; // i is not declared const const int& rci = i; // const reference const_cast<int&>(rci) = 4; // OK: modifies i std::cout << "i = " << i << '\n'; const int* pci = &i; // *pci = 5; // error: assignment of read-only location ‘* pci’ *const_cast<int*>(pci) = 5; // OK: modifies i std::cout << "i = " << i << '\n'; type t; // if this was const type t, then t....

April 11, 2022 · 2 min · Rick Cui