跳到主要内容
C++11 至 C++20 核心新特性详解与实战 | 极客日志
C++ 算法
C++11 至 C++20 核心新特性详解与实战 C++11 至 C++20 核心新特性详解与实战。内容涵盖 auto 类型推导、nullptr、智能指针、lambda 表达式、range-for、move 语义等 C++11 特性;auto 返回值、lambda 支持 auto 参数等 C++14 改进;结构化绑定、if/switch 初始化语句、constexpr if、std::optional、std::variant、std::string_view、std::filesystem 等 C++17 特性;Concepts 模板约束、Ranges 范围库、Coroutine 协程、std::span、std::format、三路比较运算符、consteval、std::jthread 及标准属性 [[...]] 机制等 C++20 特性。通过代码示例展示工程价值,助力现代 C++ 开发。
机器人 发布于 2026/3/15 更新于 2026/6/2 35 浏览C++11 新特性
这里就不详细罗列了,只是说特性有哪些
auto(类型推导)
nullptr(干掉 NULL)
智能指针(核心中的核心)
lambda 表达式
range-for(for-each)
move 语义 & 右值引用(性能关键)
C++14 新特性
auto 返回值
auto add (int a, int b) { return a + b; }
工程价值
lambda 支持 auto 参数
auto lambda = [](auto a, auto b) { return a + b; };
lambda (1 , 2 );
lambda (1.5 , 2.3 );
工程价值
C++17 新特性
结构化绑定
定义
structured bindings(结构化绑定)
std::map<int , std::string> m;
for (auto & [key, value] : m) {
std::cout << key << value;
}
工程价值
遍历 map 不再 first / second
代码可读性爆炸提升
用例
从元组/结构体解包 到 变量上面
auto [x, y] = std::pair{1, 2.0};
#include <iostream>
#include <tuple>
{
std::pair< , > p{ , };
[x, y] = p;
std::cout << << x << << y << std::endl;
}
{
t = std:: ( , , );
[a, b, c] = t;
std::cout << << a << << b << << c << std::endl;
}
{
arr[ ] = { , , };
[first, second, third] = arr;
std::cout << first << << second << << third << std::endl;
}
{
x;
y;
std::string name;
};
{
Point p{ , , };
[x_coord, y_coord, point_name] = p;
std::cout << point_name << << x_coord << << y_coord << ;
}
{
std::map< , std::string> m = {{ , }, { , }, { , }};
( & kv : m) {
std::cout << kv.first << << kv.second << std::endl;
}
( & [key, value] : m) {
std::cout << key << << value << std::endl;
}
}
{
std::pair< , std::string> p{ };
& [num, str] = p;
num = ;
std::cout << p.first << std::endl;
}
{
();
();
();
();
();
();
;
}
#include <map>
#include <string>
void example_pair ()
int
double
42
3.14
auto
"x="
", y="
void example_tuple ()
auto
make_tuple
1
"hello"
4.5
auto
"a="
", b="
", c="
void example_array ()
int
3
10
20
30
auto
" "
" "
struct
Point
int
int
void example_struct ()
100
200
"origin"
auto
": ("
", "
")\n"
void example_loop ()
int
1
"one"
2
"two"
3
"three"
for
const
auto
": "
for
const
auto
": "
void example_reference ()
int
"test"
auto
100
int main ()
example_pair
example_tuple
example_array
example_struct
example_loop
example_reference
return
0
if/switch 初始化语句
定义 if (auto it = map.find (key); it != map.end ()) {
std::cout << it->second;
}
用例 #include <iostream>
#include <map>
#include <string>
#include <vector>
#include <mutex>
#include <memory>
void example_basic () {
std::map<int , std::string> m = {{1 , "one" }, {2 , "two" }};
{
auto it = m.find (1 );
if (it != m.end ()) {
std::cout << "Found: " << it->second << std::endl;
}
}
if (auto it = m.find (1 ); it != m.end ()) {
std::cout << "Found: " << it->second << std::endl;
}
if (auto it = m.find (3 ); it != m.end ()) {
std::cout << "Found: " << it->second << std::endl;
} else {
std::cout << "Not found" << std::endl;
}
}
void example_lock () {
std::mutex mtx;
std::vector<int > shared_data;
{
std::lock_guard<std::mutex> lock (mtx) ;
if (!shared_data.empty ()) {
std::cout << "Data size: " << shared_data.size () << std::endl;
}
}
if (std::lock_guard<std::mutex> lock (mtx); !shared_data.empty ()) {
std::cout << "Data size: " << shared_data.size () << std::endl;
}
}
void example_resource () {
{
std::unique_ptr<int > ptr = std::make_unique <int >(42 );
if (ptr) {
std::cout << *ptr << std::endl;
}
}
if (auto ptr = std::make_unique <int >(42 ); ptr) {
std::cout << *ptr << std::endl;
}
}
void example_switch (int value) {
{
auto result = value * 2 ;
switch (result) {
case 2 :
std::cout << "Two" ;
break ;
default :
std::cout << "Other" ;
break ;
}
}
switch (auto result = value * 2 ; result) {
case 2 :
std::cout << "Two" ;
break ;
case 4 :
std::cout << "Four" ;
break ;
default :
std::cout << "Other: " << result;
break ;
}
}
void example_type_check () {
class Base {
public :
virtual ~Base () = default ;
};
class Derived : public Base {
public :
void specific () {}
};
Base* base_ptr = new Derived ();
{
Derived* derived = dynamic_cast <Derived*>(base_ptr);
if (derived) {
derived->specific ();
}
}
if (Derived* derived = dynamic_cast <Derived*>(base_ptr); derived) {
derived->specific ();
}
delete base_ptr;
}
#include <system_error>
#include <fstream>
void example_error_handling () {
if (std::ifstream file{"data.txt" }; file.is_open ()) {
std::string content;
std::getline (file, content);
std::cout << "Content: " << content << std::endl;
} else {
std::cout << "Failed to open file" << std::endl;
}
}
void example_multi_condition () {
std::vector<int > vec = {1 , 2 , 3 , 4 , 5 };
{
auto it = std::find (vec.begin (), vec.end (), 3 );
if (it != vec.end () && *it > 2 ) {
std::cout << "Found and value > 2" << std::endl;
}
}
if (auto it = std::find (vec.begin (), vec.end (), 3 ); it != vec.end () && *it > 2 ) {
std::cout << "Found and value > 2" << std::endl;
}
}
int main () {
example_basic ();
example_lock ();
example_resource ();
example_switch (2 );
example_type_check ();
example_error_handling ();
example_multi_condition ();
return 0 ;
}
constexpr if - 编译期条件判断 #include <iostream>
#include <type_traits>
#include <vector>
#include <string>
template <typename T>
auto get_value (T t) {
if constexpr (std::is_pointer_v<T>) {
std::cout << "Pointer: " ;
return *t;
} else {
std::cout << "Value: " ;
return t;
}
}
void example_basic () {
int x = 42 ;
int * ptr = &x;
std::cout << get_value (x) << std::endl;
std::cout << get_value (ptr) << std::endl;
}
template <typename T>
void process (T value) {
if constexpr (std::is_integral_v<T>) {
std::cout << "Integral: " << value * 2 << std::endl;
} else if constexpr (std::is_floating_point_v<T>) {
std::cout << "Floating: " << value * 1.5 << std::endl;
} else if constexpr (std::is_pointer_v<T>) {
std::cout << "Pointer to: " << *value << std::endl;
} else {
std::cout << "Other type" << std::endl;
}
}
template <int N>
constexpr int factorial () {
if constexpr (N <= 1 ) {
return 1 ;
} else {
return N * factorial <N - 1 >();
}
}
template <typename Container>
void print_container (const Container& container) {
if constexpr (std::is_same_v<Container, std::string>) {
std::cout << "String: " << container << std::endl;
} else {
std::cout << "Container elements: " ;
for (const auto & elem : container) {
std::cout << elem << " " ;
}
std::cout << std::endl;
}
}
template <typename T, typename = void >
struct has_size_method : std::false_type {};
template <typename T>
struct has_size_method <T, std::void_t <decltype (std::declval <T>().size ())>> : std::true_type {};
template <typename T>
void check_size (const T& obj) {
if constexpr (has_size_method<T>::value) {
std::cout << "Has size: " << obj.size () << std::endl;
} else {
std::cout << "No size method" << std::endl;
}
}
template <typename T>
class MyClass {
public :
void process () {
if constexpr (std::is_same_v<T, int >) {
std::cout << "Processing int type" << std::endl;
} else if constexpr (std::is_same_v<T, double >) {
std::cout << "Processing double type" << std::endl;
} else {
std::cout << "Processing generic type" << std::endl;
}
}
};
template <typename T>
constexpr auto type_name () {
if constexpr (std::is_same_v<T, int >) {
return "int" ;
} else if constexpr (std::is_same_v<T, double >) {
return "double" ;
} else if constexpr (std::is_same_v<T, std::string>) {
return "std::string" ;
} else {
return "unknown" ;
}
}
template <typename T>
T parse_string (const std::string& str) {
if constexpr (std::is_same_v<T, int >) {
return std::stoi (str);
} else if constexpr (std::is_same_v<T, double >) {
return std::stod (str);
} else if constexpr (std::is_same_v<T, float >) {
return std::stof (str);
} else {
static_assert (false , "Unsupported type for parsing" );
}
}
template <int N>
struct Fibonacci {
static constexpr int value = []() {
if constexpr (N <= 1 ) {
return N;
} else {
return Fibonacci<N - 1 >::value + Fibonacci<N - 2 >::value;
}
}();
};
template <typename Func>
auto measure_time (Func&& func) {
if constexpr (std::is_same_v<decltype (func()), void >) {
auto start = std::chrono::high_resolution_clock::now ();
func ();
auto end = std::chrono::high_resolution_clock::now ();
return end - start;
} else {
auto start = std::chrono::high_resolution_clock::now ();
auto result = func ();
auto end = std::chrono::high_resolution_clock::now ();
return std::make_pair (result, end - start);
}
}
int main () {
example_basic ();
process (10 );
process (3.14 );
int y = 5 ;
process (&y);
std::cout << "Factorial of 5: " << factorial <5 >() << std::endl;
std::string str = "hello" ;
std::vector<int > vec = {1 , 2 , 3 };
print_container (str);
print_container (vec);
check_size (str);
check_size (10 );
MyClass<int > int_obj;
MyClass<double > double_obj;
MyClass<std::string> str_obj;
int_obj.process ();
double_obj.process ();
str_obj.process ();
std::cout << "Type: " << type_name <int >() << std::endl;
std::cout << "Type: " << type_name <std::string>() << std::endl;
std::cout << "Fibonacci(10): " << Fibonacci<10 >::value << std::endl;
return 0 ;
}
std::optional 详细用法 #include <iostream>
#include <optional>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
void example_basic () {
std::optional<int > opt1 = 42 ;
std::optional<std::string> opt2 = "hello" ;
std::optional<double > opt3 = 3.14 ;
std::optional<int > empty_opt;
std::optional<int > empty_opt2 = std::nullopt ;
if (opt1. has_value ()) {
std::cout << "opt1 has value: " << opt1. value () << std::endl;
}
if (opt2) {
std::cout << "opt2 has value: " << *opt2 << std::endl;
}
if (opt3) {
std::cout << "opt3 value: " << opt3. value () << std::endl;
}
try {
std::cout << "Empty opt: " << empty_opt.value () << std::endl;
} catch (const std::bad_optional_access& e) {
std::cout << "Exception: " << e.what () << std::endl;
}
}
std::optional<int > find_value (const std::vector<int >& vec, int target) {
auto it = std::find (vec.begin (), vec.end (), target);
if (it != vec.end ()) {
return *it;
}
return std::nullopt ;
}
std::optional<std::string> parse_number (int num) {
if (num >= 0 && num <= 9 ) {
return std::to_string (num);
}
return std::nullopt ;
}
void example_function_return () {
std::vector<int > numbers = {1 , 3 , 5 , 7 , 9 };
auto result = find_value (numbers, 5 );
if (result) {
std::cout << "Found: " << *result << std::endl;
}
auto not_found = find_value (numbers, 2 );
std::cout << "Value or default: " << not_found.value_or (-1 ) << std::endl;
}
class User {
public :
std::string name;
int age;
User (std::string n, int a) : name (std::move (n)), age (a) {}
void print () const {
std::cout << "User: " << name << ", Age: " << age << std::endl;
}
};
std::optional<User> find_user (const std::string& name) {
if (name == "Alice" ) {
return User{"Alice" , 30 };
} else if (name == "Bob" ) {
return User{"Bob" , 25 };
}
return std::nullopt ;
}
struct Connection {
std::optional<std::string> send_request () {
return "response" ;
}
};
std::optional<Connection> connect () {
return Connection{};
}
std::optional<std::string> parse_response (const std::string& resp) {
if (!resp.empty ()) {
return "parsed: " + resp;
}
return std::nullopt ;
}
void example_chaining () {
{
auto conn_opt = connect ();
if (conn_opt) {
auto resp_opt = conn_opt->send_request ();
if (resp_opt) {
auto parsed_opt = parse_response (*resp_opt);
if (parsed_opt) {
std::cout << *parsed_opt << std::endl;
}
}
}
}
auto result = connect ().and_then ([](Connection& conn) { return conn.send_request (); }).and_then (parse_response);
if (result) {
std::cout << "Chained result: " << *result << std::endl;
}
}
void example_with_algorithms () {
std::vector<std::optional<int >> opts = {1 , std::nullopt , 3 , std::nullopt , 5 };
std::vector<int > values;
for (const auto & opt : opts) {
if (opt) {
values.push_back (*opt);
}
}
std::vector<std::optional<int >> transformed;
std::transform (opts.begin (), opts.end (), std::back_inserter (transformed), [](const auto & opt) -> std::optional<int > {
if (opt) {
return *opt * 2 ;
}
return std::nullopt ;
});
}
class ExpensiveResource {
std::optional<std::vector<int >> cache;
public :
const std::vector<int >& get_data () {
if (!cache) {
cache = std::vector<int >{1 , 2 , 3 , 4 , 5 };
std::cout << "Initialized cache" << std::endl;
}
return *cache;
}
void clear_cache () {
cache.reset ();
}
};
enum class ErrorCode { OK, NOT_FOUND, INVALID_INPUT, TIMEOUT };
std::optional<std::string> fetch_data_modern () {
return "data" ;
}
#include <variant>
using Result = std::variant<std::string, std::nullopt_t >;
Result process_data () {
bool success = true ;
if (success) {
return "success data" ;
}
return std::nullopt ;
}
void process_if_present (const std::optional<std::string>& opt) {
if (opt) {
std::cout << "Processing: " << *opt << std::endl;
}
}
class Config {
std::optional<std::string> theme;
std::optional<int > timeout;
std::optional<bool > debug_mode;
public :
void set_theme (const std::string& t) { theme = t; }
void set_timeout (int t) { timeout = t; }
std::string get_theme () const { return theme.value_or ("default" ); }
int get_timeout () const { return timeout.value_or (30 ); }
void print () const {
std::cout << "Theme: " << get_theme () << ", Timeout: " << get_timeout () << std::endl;
}
};
int main () {
example_basic ();
example_function_return ();
auto user = find_user ("Alice" );
if (user) {
user->print ();
}
ExpensiveResource resource;
auto & data = resource.get_data ();
auto & data2 = resource.get_data ();
Config config;
config.print ();
config.set_theme ("dark" );
config.set_timeout (60 );
config.print ();
return 0 ;
}
std::variant 详细用法
定义 std::variant<int , double , std::string> v;
v = 10 ;
v = "hello" ;
std::visit ([](auto && arg) { std::cout << arg; }, v);
std::visit std::variant<int , double , std::string> v = "world" ;
std::visit ([](auto && arg) {
using T = std::decay_t <decltype (arg)>;
if constexpr (std::is_same_v<T, int >) {
std::cout << "int: " << arg * 2 << std::endl;
} else if constexpr (std::is_same_v<T, double >) {
std::cout << "double: " << arg + 0.5 << std::endl;
} else if constexpr (std::is_same_v<T, std::string>) {
std::cout << "string length: " << arg.size () << std::endl;
}
}, v);
variant 当前持有哪种类型
visit 自动调用 lambda
arg 的真实类型在 编译期确定
零运行时 RTTI / 零 dynamic_cast
std::variant<int , double > a = 3 ;
std::variant<int , double > b = 4.5 ;
std::visit ([](auto x, auto y) {
std::cout << x + y << std::endl;
}, a, b);
std::decay_t<> 作用 auto && arg = ...;
decay_t <decltype (arg)>
int x = 10 ;
auto && arg = x;
const int y = 20 ;
auto && arg = y;
结论 : decltype(arg) 会保留:1、引用(& / &&); 2、const / volatile
二、那 std::decay_t 是干嘛的? 2️⃣ std::decay<T> 做了什么?
std::decay<T> ≈ '函数参数退化规则'
原类型 decay 后 int&intconst int&intint&&intconst intintT[N]T*T()T(*)()
三、合起来看:std::decay_t<decltype(arg)>
decay_t <decltype (arg)>
std::decay_t <...>
std::visit ([](auto && arg) {
using T = std::decay_t <decltype (arg)>;
}, v);
variant 内类型 arg 实际类型 T 最终类型 intint&intdoubledouble&doublestd::stringstd::string&std::string
四、为什么不能直接用 decltype(arg)?
if constexpr (std::is_same_v<decltype (arg), int >) { ... }
using T = std::decay_t <decltype (arg)>;
if constexpr (std::is_same_v<T, int >) { ... }
具体用例 #include <iostream>
#include <variant>
#include <string>
#include <vector>
#include <type_traits>
#include <cassert>
void example_basic () {
std::variant<int , double , std::string> v;
v = 42 ;
std::cout << "Holds int: " << std::get <int >(v) << std::endl;
v = 3.14 ;
std::cout << "Holds double: " << std::get <double >(v) << std::endl;
v = "hello" ;
std::cout << "Holds string: " << std::get <std::string>(v) << std::endl;
std::cout << "Current index: " << v.index () << std::endl;
if (std::holds_alternative <std::string>(v)) {
std::cout << "Currently holds a string" << std::endl;
}
try {
std::cout << std::get <double >(v) << std::endl;
} catch (const std::bad_variant_access& e) {
std::cout << "Bad access: " << e.what () << std::endl;
}
}
struct PrintVisitor {
void operator () (int i) const {
std::cout << "int: " << i << std::endl;
}
void operator () (double d) const {
std::cout << "double: " << d << std::endl;
}
void operator () (const std::string& s) const {
std::cout << "string: " << s << std::endl;
}
};
void example_visitor () {
std::variant<int , double , std::string> v = "test" ;
std::visit (PrintVisitor{}, v);
auto lambda_visitor = [](auto && arg) {
using T = std::decay_t <decltype (arg)>;
if constexpr (std::is_same_v<T, int >) {
std::cout << "Got int: " << arg << std::endl;
} else if constexpr (std::is_same_v<T, double >) {
std::cout << "Got double: " << arg << std::endl;
} else if constexpr (std::is_same_v<T, std::string>) {
std::cout << "Got string: " << arg << std::endl;
}
};
v = 10 ;
std::visit (lambda_visitor, v);
v = 2.5 ;
std::visit (lambda_visitor, v);
}
std::variant<std::string, std::runtime_error> parse_input (const std::string& input) {
if (input.empty ()) {
return std::runtime_error ("Empty input" );
}
if (input[0 ] == 'E' ) {
return std::runtime_error ("Input starts with E" );
}
return "Processed: " + input;
}
void example_error_handling () {
auto result = parse_input ("" );
std::visit ([](auto && arg) {
using T = std::decay_t <decltype (arg)>;
if constexpr (std::is_same_v<T, std::string>) {
std::cout << "Success: " << arg << std::endl;
} else if constexpr (std::is_same_v<T, std::runtime_error>) {
std::cout << "Error: " << arg.what () << std::endl;
}
}, result);
}
struct TreeNode ;
using TreeNodeVariant = std::variant<int , std::unique_ptr<TreeNode>>;
struct TreeNode {
TreeNodeVariant left;
TreeNodeVariant right;
int value;
TreeNode (int val, TreeNodeVariant l, TreeNodeVariant r) : value (val), left (std::move (l)), right (std::move (r)) {}
};
int calculate_tree (const TreeNodeVariant& node) {
return std::visit ([](auto && arg) -> int {
using T = std::decay_t <decltype (arg)>;
if constexpr (std::is_same_v<T, int >) {
return arg;
} else {
auto & tree = *arg;
int left_val = calculate_tree (tree.left);
int right_val = calculate_tree (tree.right);
return tree.value + left_val + right_val;
}
}, node);
}
class Connection {
public :
enum State { Disconnected, Connecting, Connected, Error };
private :
std::variant<struct DisconnectedState, struct ConnectingState, struct ConnectedState, struct ErrorState> state;
public :
Connection () : state (DisconnectedState{}) {}
void connect () {
state = std::visit ([](auto && s) -> decltype (state) {
using T = std::decay_t <decltype (s)>;
if constexpr (std::is_same_v<T, DisconnectedState>) {
std::cout << "Starting connection..." << std::endl;
return ConnectingState{};
} else if constexpr (std::is_same_v<T, ConnectingState>) {
std::cout << "Already connecting..." << std::endl;
return s;
} else if constexpr (std::is_same_v<T, ConnectedState>) {
std::cout << "Already connected" << std::endl;
return s;
} else {
std::cout << "Cannot connect from error state" << std::endl;
return s;
}
}, state);
}
void print_state () const {
std::cout << "Current state index: " << state.index () << std::endl;
}
};
struct JSONNull {};
using JSONValue = std::variant<JSONNull, bool , int , double , std::string, std::vector<JSONValue>, std::map<std::string, JSONValue>>;
void print_json (const JSONValue& value, int indent = 0 ) {
std::string spaces (indent * 2 , ' ' ) ;
std::visit ([&](auto && arg) {
using T = std::decay_t <decltype (arg)>;
if constexpr (std::is_same_v<T, JSONNull>) {
std::cout << spaces << "null" ;
} else if constexpr (std::is_same_v<T, bool >) {
std::cout << spaces << (arg ? "true" : "false" );
} else if constexpr (std::is_same_v<T, int >) {
std::cout << spaces << arg;
} else if constexpr (std::is_same_v<T, double >) {
std::cout << spaces << arg;
} else if constexpr (std::is_same_v<T, std::string>) {
std::cout << spaces << "\"" << arg << "\"" ;
} else if constexpr (std::is_same_v<T, std::vector<JSONValue>>) {
std::cout << spaces << "[\n" ;
for (const auto & elem : arg) {
print_json (elem, indent + 1 );
std::cout << ",\n" ;
}
std::cout << spaces << "]" ;
} else if constexpr (std::is_same_v<T, std::map<std::string, JSONValue>>) {
std::cout << spaces << "{\n" ;
for (const auto & [key, val] : arg) {
std::cout << spaces << " \"" << key << "\": " ;
print_json (val, 0 );
std::cout << ",\n" ;
}
std::cout << spaces << "}" ;
}
}, value);
}
using Callback = std::variant<std::function<void (int )>, std::function<void (std::string)>, std::function<void (double )>>;
class EventDispatcher {
std::vector<Callback> callbacks;
public :
void add_callback (Callback cb) {
callbacks.push_back (std::move (cb));
}
void dispatch (int value) {
for (auto & cb : callbacks) {
if (auto * func = std::get_if<std::function<void (int )>>(&cb)) {
(*func)(value);
}
}
}
void dispatch (const std::string& value) {
for (auto & cb : callbacks) {
if (auto * func = std::get_if<std::function<void (std::string)>>(&cb)) {
(*func)(value);
}
}
}
};
void example_get_if () {
std::variant<int , std::string> v = "hello" ;
if (auto * str_ptr = std::get_if <std::string>(&v)) {
std::cout << "String value: " << *str_ptr << std::endl;
}
if (auto * int_ptr = std::get_if <int >(&v)) {
std::cout << "Int value: " << *int_ptr << std::endl;
} else {
std::cout << "Not holding int" << std::endl;
}
}
template <typename ... Ts>
struct VariantWrapper {
std::variant<Ts...> var;
template <typename Func>
auto and_then (Func&& func) {
return std::visit ([&func](auto && arg) {
return func (std::forward<decltype (arg)>(arg));
}, var);
}
};
void example_performance () {
std::variant<int , double , std::array<char , 100>> v;
std::cout << "Size of variant: " << sizeof (v) << " bytes" << std::endl;
union TraditionalUnion {
int i;
double d;
char str[100 ];
};
std::cout << "Size of union: " << sizeof (TraditionalUnion) << " bytes" << std::endl;
}
int main () {
example_basic ();
example_visitor ();
example_error_handling ();
example_get_if ();
example_performance ();
Connection conn;
conn.connect ();
conn.print_state ();
JSONValue json = std::map<std::string, JSONValue>{{"name" , "John" }, {"age" , 30 }, {"scores" , std::vector<JSONValue>{85 , 90 , 78 }}, {"active" , true }};
std::cout << "\nJSON output:\n" ;
print_json (json);
std::cout << std::endl;
return 0 ;
}
std::string_view 详细用法 void print (std::string_view sv) {
std::cout << sv;
}
print ("hello" );
print (std::string ("world" ));
#include <iostream>
#include <string_view>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>
void example_basic () {
const char * cstr = "Hello, World!" ;
std::string_view sv1 (cstr) ;
std::cout << "sv1: " << sv1 << ", size: " << sv1. size () << std::endl;
std::string str = "Hello from std::string" ;
std::string_view sv2 (str) ;
std::cout << "sv2: " << sv2 << std::endl;
std::string_view sv3 = "String literal" ;
std::cout << "sv3: " << sv3 << std::endl;
std::string_view sv4 = sv1. substr (0 , 5 );
std::cout << "sv4 (substr): " << sv4 << std::endl;
const char * data = "Raw data" ;
std::string_view sv5 (data, 3 ) ;
std::cout << "sv5 (pointer+len): " << sv5 << std::endl;
char arr[] = {'H' , 'i' , '!' , '\0' };
std::string_view sv6 (arr) ;
std::cout << "sv6 (array): " << sv6 << std::endl;
}
void print_string (std::string_view sv) {
std::cout << "Received: " << sv << ", Length: " << sv.length () << ", Data: " << sv.data () << std::endl;
}
std::string_view find_word (std::string_view text, std::string_view word) {
size_t pos = text.find (word);
if (pos != std::string_view::npos) {
return text.substr (pos, word.length ());
}
return {};
}
void example_function_parameters () {
print_string ("C string" );
std::string str = "std::string" ;
print_string (str);
std::string_view sv = "string_view" ;
print_string (sv);
std::string_view text = "The quick brown fox jumps over the lazy dog" ;
std::string_view found = find_word (text, "fox" );
if (!found.empty ()) {
std::cout << "Found: " << found << std::endl;
}
}
void example_string_operations () {
std::string_view sv = "Hello, World! Programming is fun!" ;
size_t pos = sv.find ("World" );
if (pos != std::string_view::npos) {
std::cout << "'World' found at position: " << pos << std::endl;
}
std::string_view sv2 = "Hello" ;
if (sv.compare (0 , 5 , sv2) == 0 ) {
std::cout << "Starts with 'Hello'" << std::endl;
}
std::string_view sv3 = sv;
sv3. remove_prefix (7 );
std::cout << "After remove_prefix: " << sv3 << std::endl;
sv3. remove_suffix (19 );
std::cout << "After remove_suffix: " << sv3 << std::endl;
if (sv.starts_with ("Hello" )) {
std::cout << "Starts with Hello" << std::endl;
}
if (sv.ends_with ("fun!" )) {
std::cout << "Ends with fun!" << std::endl;
}
}
void example_with_algorithms () {
std::vector<std::string_view> words = {"apple" , "banana" , "cherry" , "date" , "elderberry" };
auto it = std::find_if (words.begin (), words.end (), [](std::string_view sv) {
return sv.find ('a' ) != std::string_view::npos;
});
if (it != words.end ()) {
std::cout << "First word with 'a': " << *it << std::endl;
}
std::sort (words.begin (), words.end ());
std::cout << "Sorted words: " ;
for (const auto & w : words) {
std::cout << w << " " ;
}
std::cout << std::endl;
struct StringViewCompare {
bool operator () (std::string_view a, std::string_view b) const {
return a < b;
}
};
std::map<std::string_view, int , StringViewCompare> word_count;
word_count["apple" ] = 3 ;
word_count["banana" ] = 2 ;
}
#include <chrono>
void process_string (const std::string& str) {
volatile size_t len = str.length ();
(void )len;
}
void process_string_view (std::string_view sv) {
volatile size_t len = sv.length ();
(void )len;
}
void example_performance () {
std::string long_string (10000 , 'x' ) ;
auto start1 = std::chrono::high_resolution_clock::now ();
for (int i = 0 ; i < 10000 ; ++i) {
process_string (long_string);
}
auto end1 = std::chrono::high_resolution_clock::now ();
auto start2 = std::chrono::high_resolution_clock::now ();
for (int i = 0 ; i < 10000 ; ++i) {
process_string_view (long_string);
}
auto end2 = std::chrono::high_resolution_clock::now ();
auto time1 = std::chrono::duration_cast <std::chrono::microseconds>(end1 - start1);
auto time2 = std::chrono::duration_cast <std::chrono::microseconds>(end2 - start2);
std::cout << "std::string time: " << time1. count () << "μs" << std::endl;
std::cout << "std::string_view time: " << time2. count () << "μs" << std::endl;
std::cout << "Speedup: " << static_cast <double >(time1. count ()) / time2. count () << "x" << std::endl;
}
std::vector<std::string_view> split_string (std::string_view str, std::string_view delimiters) {
std::vector<std::string_view> tokens;
size_t start = 0 ;
size_t end = 0 ;
while ((end = str.find_first_of (delimiters, start)) != std::string_view::npos) {
if (end != start) {
tokens.push_back (str.substr (start, end - start));
}
start = end + 1 ;
}
if (start < str.length ()) {
tokens.push_back (str.substr (start));
}
return tokens;
}
void example_parsing () {
std::string_view csv_line = "apple,banana,cherry,date,elderberry" ;
auto fruits = split_string (csv_line, "," );
std::cout << "Parsed fruits:" << std::endl;
for (const auto & fruit : fruits) {
std::cout << " - " << fruit << std::endl;
}
std::string_view config_line = "timeout = 30" ;
size_t eq_pos = config_line.find ('=' );
if (eq_pos != std::string_view::npos) {
std::string_view key = config_line.substr (0 , eq_pos);
std::string_view value = config_line.substr (eq_pos + 1 );
key.remove_prefix (std::min (key.find_first_not_of (" " ), key.size ()));
key.remove_suffix (key.size () - key.find_last_not_of (" " ) - 1 );
value.remove_prefix (std::min (value.find_first_not_of (" " ), value.size ()));
value.remove_suffix (value.size () - value.find_last_not_of (" " ) - 1 );
std::cout << "Key: '" << key << "', Value: '" << value << "'" << std::endl;
}
}
void example_pitfalls () {
std::string_view dangerous;
{
std::string temp = "temporary string" ;
dangerous = temp;
}
std::string permanent = "permanent string" ;
std::string_view safe = permanent;
char buffer[] = {'H' , 'e' , 'l' , 'l' , 'o' };
std::string_view sv (buffer, 5 ) ;
std::string_view sv2 = "Hello" ;
if (sv2. data ()[sv2. size ()] == '\0' ) {
std::cout << "Properly null-terminated" << std::endl;
}
char mutable_buffer[] = "Hello" ;
std::string_view sv3 (mutable_buffer) ;
std::cout << "Before: " << sv3 << std::endl;
mutable_buffer[0 ] = 'J' ;
std::cout << "After: " << sv3 << std::endl;
}
constexpr std::string_view operator "" _sv(const char * str, size_t len) {
return std::string_view (str, len);
}
void example_user_literal () {
auto sv = "Hello World" _sv;
static_assert (std::is_same_v<decltype (sv), std::string_view>);
std::cout << "Using literal: " << sv << ", size: " << sv.size () << std::endl;
}
constexpr std::string_view compile_time_str = "Compile time string" ;
constexpr bool starts_with_compile (std::string_view sv, std::string_view prefix) {
return sv.size () >= prefix.size () && sv.substr (0 , prefix.size ()) == prefix;
}
void example_constexpr () {
static_assert (compile_time_str.size () == 19 );
static_assert (starts_with_compile (compile_time_str, "Compile" ));
constexpr std::string_view local_constexpr = "Local constexpr" ;
static_assert (local_constexpr.find ("const" ) != std::string_view::npos);
}
class StringViewWrapper {
std::string_view view;
public :
StringViewWrapper (const char * str) : view (str) {}
StringViewWrapper (const std::string& str) : view (str) {}
StringViewWrapper (std::string_view sv) : view (sv) {}
std::string to_string () const {
return std::string (view);
}
bool contains (std::string_view substr) const {
return view.find (substr) != std::string_view::npos;
}
std::string_view substr (size_t pos, size_t count = std::string_view::npos) const {
return view.substr (pos, count);
}
friend std::ostream& operator <<(std::ostream& os, const StringViewWrapper& wrapper) {
return os << wrapper.view;
}
};
int main () {
example_basic ();
example_function_parameters ();
example_string_operations ();
example_with_algorithms ();
example_parsing ();
example_pitfalls ();
example_user_literal ();
example_constexpr ();
example_performance ();
StringViewWrapper wrapper1 ("C string" ) ;
StringViewWrapper wrapper2 (std::string("std::string" )) ;
StringViewWrapper wrapper3 ("string_view" _sv) ;
std::cout << "Wrapper1: " << wrapper1 << std::endl;
std::cout << "Contains 'str': " << wrapper1. contains ("str" ) << std::endl;
return 0 ;
}
std::filesystem #include <filesystem>
namespace fs = std::filesystem;
for (auto & p : fs::directory_iterator ("data" )) {
std::cout << p.path () << std::endl;
}
文件遍历、路径拼接
可逐步替代 Qt 的 QFileInfo(或混用)
C++20 新特性
可以把 C++20 理解为:模板更像人话 + 算法更像流水线 + 异步更像同步
一、Concepts(模板约束)
是什么
以前(C++17) template <typename T>
T add (T a, T b) {
return a + b;
}
C++20 #include <concepts>
template <std::integral T>
T add (T a, T b) {
return a + b;
}
add (1 , 2 );
add (1.2 , 2.3 );
工程价值
二、Ranges(算法 & 容器革命)
是什么
示例 #include <ranges>
#include <vector>
#include <iostream>
int main () {
std::vector<int > v = {1 , 2 , 3 , 4 , 5 , 6 };
auto even = v | std::views::filter ([](int x) { return x % 2 == 0 ; }) | std::views::transform ([](int x) { return x * 10 ; });
for (int x : even) {
std::cout << x << " " ;
}
}
auto result = numbers | rv::filter ([](int n) { return n % 2 == 0 ; })
| rv::transform ([](int n) { return n * n; })
| rv::take (3 );
工程价值
数据处理'管道化'
非常适合 UI / 数据流 / 解析逻辑
三、Coroutine(协程)(进阶)
是什么
极简示例(概念理解) #include <coroutine>
struct Task {
struct promise_type {
Task get_return_object () { return {}; }
std::suspend_never initial_suspend () { return {}; }
std::suspend_never final_suspend () noexcept { return {}; }
void return_void () {}
void unhandled_exception () {}
};
};
Task foo () {
co_return ;
}
工程价值 ⚠️ Qt 目前更多是 concept + future + thread,协程别急
四、std::span(安全的数组视图)
是什么
非拥有的连续内存视图(安全版 T* + size)
示例 #include <span>
#include <vector>
#include <iostream>
void process (std::span<int > data) {
for (int x : data) {
std::cout << x << " " ;
}
}
int main () {
std::vector<int > v = {1 , 2 , 3 };
process (v);
}
工程价值
五、std::format(现代格式化)⭐⭐⭐⭐⭐
是什么
C++ 原生 fmt,干掉 printf / ostringstream
示例 #include <format>
#include <iostream>
int main () {
int id = 10 ;
double value = 3.14 ;
std::cout << std::format("id={}, value={:.2f}" , id, value);
}
工程价值
六、std::ranges::sort 等算法升级 #include <ranges>
#include <vector>
std::vector<int > v = {4 , 1 , 3 , 2 };
std::ranges::sort (v);
std::sort (v.begin (), v.end ());
七、三路比较 <=>(太空船运算符)
是什么
示例 #include <compare>
struct Point {
int x;
int y;
auto operator <=>(const Point&) const = default ;
};
工程价值
八、consteval / constexpr 升级
是什么 consteval int square (int x) {
return x * x;
}
int main () {
int a = square (5 );
}
九、std::jthread(自动 join 的线程)
是什么
示例 #include <thread>
#include <iostream>
void work () {
std::cout << "working\n" ;
}
int main () {
std::jthread t (work) ;
}
工程价值
十、std::stop_token(线程取消) #include <thread>
#include <iostream>
void work (std::stop_token st) {
while (!st.stop_requested ()) {
}
}
int main () {
std::jthread t (work) ;
t.request_stop ();
}
十一、[[...]] if (error) [[unlikely]] {
return ;
}
好,这个点问得非常专业 👍
你说的 [[...]] 不是'一个特性',而是 C++11 引入、在 C++17 / C++20 里逐步增强的一整套:
👉 标准属性(attributes)机制 。
我给你来一版从底层认知 → 常用属性 → 工程实战 → 易踩坑 的完整讲解。
[[...]] 是 给编译器看的'元信息'
不改变语义,只影响:
编译器诊断(warning / error)
优化策略
代码意图表达
属性不会改变程序逻辑,只是'提示 / 约束 / 标注'
__attribute__((unused))
__declspec(noreturn)
[[nodiscard]]
[[maybe_unused]]
[[likely]]
[[nodiscard]]
int calc () {
return 42 ;
}
int main () {
calc ();
int x = calc ();
}
错误码
资源句柄
std::optional / expected
void foo ([[maybe_unused]] int debugFlag) {
}
3️⃣ [[likely]] / [[unlikely]](C++20)
if (value < 0 ) [[unlikely]] {
return ;
}
4️⃣ [[fallthrough]](switch 专用)
switch (x) {
case 1 :
doA ();
[[fallthrough]];
case 2 :
doB ();
break ;
}
[[deprecated ("Use newFunc instead" )]]
void oldFunc () {}
[[nodiscard]]
int foo () ;
[[deprecated]]
struct A {};
void bar ([[maybe_unused]] int ) ;
[[likely]]
if (...) {}
属性 宏 作用于语法层 文本替换 有作用域 无作用域 可被工具识别 不易分析 标准化 编译器私有
[[gnu::unused]]
[[msvc::noinline]]
[[nodiscard]]
bool loadConfig () ;
if (!ptr) [[unlikely]] {
return ;
}
switch (state) {
case A:
...
[[fallthrough]];
case B:
...
}
[[deprecated ("Use NewApi" )]]
void OldApi () ;
[[nodiscard]]
int x = 10 ;
if (hotPath) [[likely]] {
...
}
[[...]] 是 写给'编译器 + 未来维护者'的注释
不是给机器跑逻辑的
十二、std::remove_cvref_t using T = std::remove_cvref_t <decltype (arg)>;
十三、constexpr 容器(重要但低调) constexpr std::vector<int > make () {
return {1 , 2 , 3 };
}
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online