C++ 17 折叠表达式
C++17 引入的折叠表达式(Fold Expression)主要是给可变参数模板服务的。它的意义很直接:把一包参数按照某个运算符“折叠”成一个表达式,省掉以前那种递归展开模板的写法。
1. 为什么需要折叠表达式?在 C++17 之前,如果我们想对一组参数求和,常见写法通常是递归模板:
12345678910int sum(){ return 0;}template <typename T, typename... Args>T sum(T first, Args... args){ return first + sum(args...);}
这种写法能用,但比较啰嗦,而且可读性一般。有了折叠表达式之后,代码可以直接写成:
12345template <typename... Args>auto sum(Args... args){ return (... + args);}
明显简洁很多。
2. 基本语法折叠表达式分为四种形式:
1234( ... o ...
问题背景在 Qt QML 工程开发过程中,我一开始是用交叉编译环境把程序跑在 arm 开发板上。后来为了更方便地看桌面端 UI 效果,切回了本机桌面环境构建,结果程序在启动时直接报错:
1module "QtQuick.Dialogs" is not installed
这个问题看起来像是“模块没装”,但真正排查下来,更多时候不是没装,而是当前使用的 Qt 版本找不到和自己匹配的 QML 模块。
错误原因分析我这里的问题核心有两个:
系统里确实有 QtQuick.Dialogs
但系统包安装的是 Ubuntu 自带 Qt 版本对应的模块
项目实际使用的是另外一个单独安装的 Qt 版本
也就是说,程序构建和运行时使用的 Qt,与系统包里的 Qt 并不是一套环境。
这种情况下,哪怕你已经执行过:
1sudo apt install qml-module-qtquick-dialogs
项目仍然可能继续报错。
先确认当前项目到底用了哪个 Qt在动手编译模块之前,最好先把当前 Qt 环境查清楚,不然后面很容易装错地方。
1. 查看 qmake 版本12qmake - ...
everyday
未读Codeium简介
Codeium是一个基于尖端人工智能技术构建的免费AI代码加速工具包。它提供代码补全、智能搜索和支持20多种语言的AI聊天功能。Codeium可用于所有流行的集成开发环境(IDE),包括Visual Studio Code、IntelliJ IDEA和Eclipse。
Codeium特点
比想象中更快地获得代码补全。Codeium的生成式代码可以节省时间,帮助您更快地发布产品。
通过智能搜索找到与其意图相关的文件和代码。不再与复杂的正则表达式纠缠不清,使用我们的AI搜索来找到与您意图相关的文件和代码。
从Codeium Chat获得帮助。生成样板代码、重构代码、添加文档、解释代码、建议错误修复等等。
Codeium功能
代码补全:Codeium可以根据您当前代码的上下文自动为您完成代码。这可以节省您很多时间,特别是对于大型或复杂的项目。
智能搜索:Codeium可以搜索与您意图相关的文件和代码。这是一种快速轻松找到所需代码的好方法。
AI聊天支持:Codeium可以帮助您完成各种编码任务,例如生成样板代码、重构代码和添加文档。您还可以使用Codeium
Chat ...
C++ 17 结构化绑定
C++17 引入的结构化绑定(Structured Bindings)是一个非常有用的语言特性,使得解构和访问多个值变得更加简洁和直观。结构化绑定允许你将一个对象或数据结构的多个元素绑定到独立的变量上,这在处理返回多个值的函数或解构容器时非常方便。
语法与使用场景
解构std::tuple 在 C++17 之前,如果你有一个 std::tuple ,需要分别获取其中的元素,通常会使用 std::get:
123456789101112131415#include <tuple>#include <iostream>std::tuple<int, double, std::string> getTuple() { return {1, 3.14, "Hello"};}int main() { auto t = getTuple(); int i = std::get<0>(t); double d = std::get& ...
C++11 lambda表达式1. 简介与使用lambda的历时悠久,不过具体到C++11中,lambda函数却显得与之前C++规范下的代码在风格上有较大的区别。举例如下:
12345678910#include <iostream>int main(){auto addNums= [](int nNum1, int nNum2)->int {return nNum1 + nNum2; }; std::cout << "结果:addNums= " << addNums(11, 2); return 0;}
在上述代码中,定义了一个lambda函数,该函数接收两个参数:nNum1和nNum2,并返回两个参数的和;
在此,lambda相比于普通函数来说,少了函数名,取而代之的是一对([]);
此外,lambda函数还采用追踪的返回类型的方式声明其返回值。其余反面看起来跟普通函数定义一样。
2. lambda函数语法定义[capture] (parameters) mutable -> ...
1. auto
在 C++11 中,引入了许多新的特性,例如 auto 关键字用于自动推导变量的类型,同时结合 decltype可以明确表示函数的返回值。这些特性使得代码更加简洁和现代化,提升了编程效率和可维护性。利用这些新特性,我们能够编写出更加优雅和高效的代码。
1.1 基本推导规则当使用 auto 声明一个变量时,编译器根据初始化表达式的类型来推导变量的类型。推导的类型与初始化表达式的类型相同。使用语法如下:
1auto variable = expression; # auto 变量名 = 变量值
简单使用例子如下:
123auto x = 10; // x 的类型是 intauto y = 3.14; // y 的类型是 doubleauto z = "hello"; // z 的类型是 const char*
1.2 引用和指针如果初始化表达式是一个引用或指针,auto 推导的类型也会是对应的引用或指针类型。
123int a = 5;auto& ref = a; // ref 的类型是 int&au ...
everyday
未读WSL 中文字符编码问题在使用 Windows Subsystem for Linux (WSL) 做开发时,终端里偶尔会遇到中文显示乱码、文件名显示异常,或者 git log、ls、vim 中中文不正常的问题。这个问题大多数时候和 locale 配置、终端字体 或者 文件编码 有关系。
这篇文章把我自己排查时常用的几个方法记一下,后面再遇到类似问题可以直接照着查。
1. 先确认是不是 locale 的问题先在终端里执行:
1locale
如果输出里看到的 LANG、LC_ALL 之类不是 UTF-8,那大概率就是编码环境没配好。例如下面这种就是正常的:
123LANG=zh_CN.UTF-8LC_CTYPE="zh_CN.UTF-8"LC_NUMERIC="zh_CN.UTF-8"
如果显示成了 POSIX、C,或者根本没有 UTF-8,就需要处理一下。
2. 临时解决:先把当前终端切到 UTF-8有时候只是当前 shell 环境没带上编码设置,可以先手动执行:
12export LANG=zh_CN.UTF-8export LC_ALL= ...
C++ 17 if-switch初始化
C++17 为 if 和 switch 增加了一个很实用的小特性:可以在条件判断前先写一段初始化语句。这样既能少写一行代码,也能把变量的作用域限制在当前判断语句里,让代码更紧凑一些。
1. 为什么这个特性好用?在 C++17 之前,我们经常会这样写:
1234int value = someFunction();if (value > 0) { // do something}
这段代码当然没问题,但有一个小缺点:value 在 if 语句结束以后仍然存在。如果这个变量只是为了当前判断临时使用,那它暴露在外部作用域里就有点多余了。
C++17 允许我们把它收进 if 语句里:
123if (int value = someFunction(); value > 0) { // do something}
这样写以后,value 的作用域只在这个 if / else 结构内部,更干净。
2. if 初始化语句2.1 基本语法123if (init-statement; condi ...
C++ 17 内联变量
C++17 引入了内联变量(inline variables)这一特性,它主要用来解决“变量定义写在头文件里会重复定义”的问题。这个特性对写库、写公共配置、写静态成员变量都很实用。
1. 先看一下问题出在哪里在 C++17 之前,如果我们想在类里定义一个静态成员变量,通常要分成“声明”和“定义”两步:
1234// header.hstruct MyClass { static const int value;};
1234// source.cpp#include "header.h"const int MyClass::value = 42;
如果你把定义也写进头文件里,并且这个头文件被多个 .cpp 文件包含,那么链接阶段就很容易报 multiple definition 错误。
对于一些全局常量、配置项、或者头文件库来说,这种写法会比较麻烦,因为你总得额外找个 .cpp 去放定义。
2. C++17 的内联变量怎么写?有了 inline variable 之后,可以直接在头文件里完成定义:
123str ...
C++17 类模板参数推导
C++17 引入了类模板参数推导(Class Template Argument Deduction,简称 CTAD)这一特性。它的作用很直接:当我们构造一个类模板对象时,编译器可以根据构造函数的参数自动推导模板参数类型,这样很多场景下就不用再手写 <T> 了。
1. 为什么会有类模板参数推导?在 C++17 之前,函数模板可以自动推导类型,但类模板一般不行。比如下面这个简单的 Pair:
1234567template <typename T1, typename T2>struct Pair { T1 first; T2 second; Pair(T1 a, T2 b) : first(a), second(b) {}};
在旧写法中,必须显式写出模板参数:
1Pair<int, double> p(1, 3.14);
虽然这段代码没有问题,但很多时候模板参数其实已经完全体现在构造函数参数里了,再写一遍就显得有些重复。有了 CTAD 以后,可以直接写成:
...










