探索C++14新特性:更强大、更高效的编程

简介: 探索C++14新特性:更强大、更高效的编程

c++14并没有太大的改动,就连官方说明中也指出,c++14相对于c++11来说是一个比较小的改动,但是在很大程度上完善了c++11,所以可以说c++14就是在c++11标准上的查漏补缺。

image.png

C++14在2014年8月18日正式批准宣布,同年12月15日正式发布release版本。本文中将就变动部分做一个总结,有需要改进和提升的地方希望大家批评指正。


一、C++14新特性


1.1新的语言特性

  • 变量模板
  • 泛型 lambda
  • lambda 初始化捕获
  • 新建/删除省略
  • 放宽对 constexpr 函数的限制
  • 二进制文字
  • 数字分隔符
  • 函数的返回类型推导
  • 具有默认非静态成员初始值设定项的 聚合类。


1.2新库功能

  • std::make_unique
  • std::shared_timed_mutexstd::shared_lock
  • std::整数序列
  • 标准::交换
  • std::引用
  • 以及对现有图书馆设施的许多小改进,例如
  • 某些算法的两范围重载
  • 类型特征的类型别名版本
  • 用户定义的basic_string持续时间复杂的文字
  • ETC。


1.3变量模板


C++11及之前,我们只有针对类和函数的模板。C++14中,新增了变量模板:

template<class T>
constexpr T pi = T(3.1415926535897932385L);
template<class T>
T circular_area(T r)
{
  return pi<T> *r * r;
}

变量模板同样可以在类变量中使用:

template<class T>
class X {
  static T s;
};
template<class T>
T X<T>::s = 0;

类似函数和类模板,当变量模板被引用时,则会发生实例化。


1.4lambda 表达式的新增功能


1)泛化


支持在 lambda 表达式中使用 auto 定义变量类型:

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
  auto glambda = [](auto& a) { cout << a << " "; };
  int a[] = { 4, 2, 6, 3, 7, 5 };
  for_each(a, a + sizeof(a) / sizeof(int), glambda);
  cout << endl;
}

2)对捕获的变量和引用进行初始化

include <iostream>
using namespace std;
int main()
{
  int x = 4;
  auto y = [&r = x, x = x + 1]()->int
  {
    r += 2;
    return x * x;
  }(); 
  cout << "x = " << x << " y = " << y << endl;
}

640.png

1.5constexpr 函数可以包含多个语句

在C++11中,如果想使用constexpr方法,只能包含一个返回语句。C++14中,放宽了此要求,允许constexpr函数中声明变量,使用循环和条件语句等:

#include <iostream>
#include <cmath>
using namespace std;
constexpr bool isPrimitive(int number)
{
  if (number <= 0)
  {
    return false;
  }
  for (int i = 2; i <= sqrt(number) + 1; ++i)
  {
    if (number % i == 0)
    {
      return false;
    }
  }
  return true;
}
int main()
{
  cout << boolalpha << isPrimitive(102) << " " << isPrimitive(103);
  return 0;
}


在C++11中,我们一般需要通过递归来实现相同的功能:

constexpr bool isPrimitive(int number, int currentFactor, int maxFactor)
{
  return currentFactor == maxFactor ? true : 
      (number % currentFactor == 0 ? false : 
        isPrimitive(number, currentFactor + 1, maxFactor));
}
constexpr bool isPrimitive(int number)
{
  return number <= 0 ? false : isPrimitive(number, 2, sqrt(number) + 1);
}


1.6整型字面量


1)二进制字面量


支持使用 0b 开头的一串数字作为二进制表示的整型:

int a = 0b10101001110; // 1358


2)数字分割符


支持在数字中使用单引号进行分割(便于阅读)。在编译时,这些单引号会被忽略。

int a = 123'456'789; // 123456789


1.7返回类型自动推导


在C++14中,我们可以使用 auto 作为函数返回值并且不需要指明其返回类型的推导表达式

int x = 1;
auto f() { return x; }
/* c++11
auto f() -> decltype(x) { return x; } 
*/

这种类型推导有一些限制:

  • 一个函数中所有返回字句必须推导出相同的类型;
  • 使用 {} 包裹的数据作为返回值时,无法推导其类型;
  • 虚函数coroutine 不能被推导;
  • 函数模板中可以使用类型推导,但是其显式实例化和特化版本必须使用相同的返回类型描述符。


1.8exchange


exchange 用于移动语义,可以使用指定的新值替换掉原值,并返回原值。其定义在C++20中被简单修改如下:

template<class T, class U = T>
constexpr // since C++20
T exchange(T& obj, U&& new_value)
{
    T old_value = std::move(obj);
    obj = std::forward<U>(new_value);
    return old_value;
}


其使用如下:

#include <iostream>
#include <vector>
#include <utility>
using namespace std;
int main()
{
  vector<int> v = {5, 6, 7};
  std::exchange(v, { 1,2,3,4 });
  std::copy(begin(v), end(v), ostream_iterator<int>(cout, " "));
  cout << endl;
}


1.9quoted


该类用于字符串转义的处理。使用 out << quoted(s, delim, escape) 的形式,可以将字符串 s 的转义格式写入输出流中;使用 in >> quoted(s, delim, escape) 可以将输入流去除转义格式后写入字符串 s 中。其中,delim 指明了需要转义的字符,escape 指明了修饰该转移字符的字符:

#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
int main()
{
  stringstream ss;
  string in = "String with spaces, and embedded \"quotes\" too";
  string out;
  auto show = [&](const auto& what) 
  {
    &what == &in
      ? cout << "read in     [" << in << "]\n"
      << "stored as   [" << ss.str() << "]\n"
      : cout << "written out [" << out << "]\n\n";
  };
  ss << quoted(in); 
  show(in);
  ss >> quoted(out);
  show(out);
  ss.str(""); 
  in = "String with spaces, and embedded $quotes$ too";
  const char delim{ '$' };
  const char escape{ '%' };
  ss << quoted(in, delim, escape);
  show(in);
  ss >> quoted(out, delim, escape);
  show(out);
}

【文章福利】小编推荐自己的Linux C++技术交流群:【1106675687】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!前100名进群领取,额外赠送大厂面试题。


二、C++14经常考到的知识点


2.1C++14引入了哪些新特性?


C++14引入了一些新特性,包括但不限于以下内容:

  1. 通用Lambda表达式:允许在lambda函数中使用auto关键字来推导参数类型。
  2. 自动返回类型推导:允许使用auto关键字自动推导函数返回值类型。
  3. 初始化列表的泛型支持:可以使用auto关键字在初始化列表中推导元素类型。
  4. 带有二进制分隔符的整数字面量:可以在整数常量中使用单撇号作为分隔符,提高可读性。
  5. constexpr函数的扩展:constexpr函数可以包含更多操作,例如循环和条件判断。
  6. 变长参数模板(Variadic Templates)的改进:支持递归处理变长参数模板的展开。
  7. 返回void类型的lambda表达式:允许定义返回void类型的lambda函数。


2.2C++14中auto关键字的用法和限制是什么?

在C++14中,auto关键字用于自动类型推导,可以根据初始化表达式的类型来确定变量的类型。它的使用和限制如下:

  1. 自动类型推导:使用auto关键字声明变量时,编译器会根据初始化表达式的类型自动推导出变量的类型。
    auto x = 42; // 推导为int型 auto name = "John"; // 推导为const char*型
  2. 声明时必须初始化:使用auto声明变量时,必须进行初始化。因为编译器需要根据初始化表达式来推导出变量的类型。
    auto y; // 错误,未初始化
  3. 可与引用结合使用:auto关键字可以与引用一起使用,从而推导出引用的类型。
    int a = 10; auto& ref = a; // 推导为int&型,ref是a的引用
  4. 不支持数组或函数指针:auto不能直接用于数组或函数指针的声明。但可以通过decltype结合auto来实现对数组或函数指针类型进行推导。
    int arr[] = {1, 2, 3}; auto arrRef = arr; // 错误,无法推导arr的数组类型 decltype(arr) arrType; // 使用decltype获取arr的数组类型并声明arrType void foo(); auto funcPtr = foo; // 错误,无法推导foo的函数指针类型 decltype(foo)* funcPtrType; // 使用decltype获取foo的函数指针类型并声明funcPtrType

需要注意的是,auto在C++14中的用法和限制可能与之后的标准(如C++17、C++20等)有所不同,具体取决于编译器和所使用的标准版本。


2.3C++14中如何使用Lambda表达式?有什么改进?

在C++14中,使用Lambda表达式的语法与之前的C++版本相似。Lambda表达式是一种可以在代码中内联定义匿名函数的方式。


下面是一个使用Lambda表达式的示例:

#include <iostream>
#include <vector>
#include <algorithm>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    // 使用Lambda表达式进行遍历打印
    std::for_each(numbers.begin(), numbers.end(), [](int num) {
        std::cout << num << " ";
    });
    return 0;
}


在Lambda表达式中,方括号 [] 用于捕获外部变量(可选)。小括号 ( ) 内指定参数列表(可选),箭头 -> 后面指定返回类型(可选)。


C++14对于Lambda表达式有一些改进,其中最显著的改进是可以自动推导返回类型。这意味着你不需要显式地指定返回类型,编译器会根据表达式体来推断返回类型。


以下是一个示例:

auto lambda = [](int a, int b) {
    return a + b;
};


在上述示例中,我们没有显式指定返回类型,但编译器会自动推断出返回类型为整数(因为a和b都是整数)。


此外,在C++14中还引入了泛型lambda,使得可以在lambda函数中使用auto关键字作为参数类型,更加灵活和方便。


2.4C++14对于constexpr关键字有何改进?


C++14对于constexpr关键字进行了一些改进,使得其更加灵活和强大。在C++11中,constexpr只能用于表示常量表达式的函数和构造函数,而在C++14中,它还可以用于一些额外的情况。


首先,在C++14中,constexpr函数可以包含一些非常量表达式的逻辑,只要这部分逻辑在运行时不会执行即可。这意味着我们可以在constexpr函数内使用循环、条件语句等非常量表达式的控制流程。


其次,C++14引入了对变量模板(Variable Templates)的支持,并且允许将变量声明为constexpr。这样我们就可以定义并初始化一个编译期间可计算的常量变量。

此外,在C++14中,对于某些标准库类型(如数组、字符串等),它们也提供了更多的支持以便于使用在编译期间计算出来的常量值。


2.5C++14中提供了哪些新的标准库组件和功能?


C++14引入了一些新的标准库组件和功能,以下是其中的一些主要特性:


  1. std::make_unique:提供了在堆上创建 unique_ptr 对象的便捷方式。
  2. std::integer_sequence:支持编译时整数序列的操作,用于元编程。
  3. std::user_defined_literals:允许用户定义自己的字面量后缀,扩展了语言的表达能力。
  4. 通用 lambda 表达式:允许使用 auto 参数声明参数类型,使得 lambda 表达式更加灵活。
  5. 变长模板参数折叠(Variadic template parameter packs expansion):可以将多个参数打包传递给模板函数或类,并且可以对它们进行展开操作。
  6. std::experimental 命名空间:引入了一些实验性质的标准库组件,如 optional、any、string_view 等。


2.6在C++14中,变长参数模板是如何使用的?


在C++14中,可以使用变长参数模板(Variadic Templates)来处理可变数量的函数参数。通过使用递归展开参数包的方式,可以灵活地处理任意数量的参数。


下面是一个示例:

#include <iostream>
// 递归终止条件:当没有剩余参数时停止递归
void printArgs() {
    std::cout << "All arguments have been printed." << std::endl;
}
// 可变参数模板:展开第一个参数并调用自身处理剩余参数
template<typename T, typename... Args>
void printArgs(T first, Args... args) {
    std::cout << "Argument: " << first << std::endl;
    printArgs(args...); // 递归调用自身处理剩余参数
}
int main() {
    printArgs(1, "Hello", 3.14, 'A');
    return 0;
}


输出结果:

Argument: 1
Argument: Hello
Argument: 3.14
Argument: A
All arguments have been printed.


在上述代码中,printArgs 是一个可变参数模板函数。它首先处理第一个传入的参数 first,然后递归地调用自身处理剩余的 args 参数。当所有参数都被展开并打印完毕后,最终会到达递归终止条件。


这种方式使得我们能够在编译时处理不同数量和类型的函数参数,并且可以灵活地进行操作。


2.7在C++14中,是否允许在lambda函数内定义其他函数或类?


在C++14中,lambda函数内是不允许定义其他函数或类的。Lambda函数是一个匿名的函数对象,它通常用于简化代码,提供一种在局部范围内编写小型函数的方式。Lambda函数本质上是一个闭包,它可以捕获外部作用域中的变量,并且具有与普通函数相似的行为。


然而,在C++17中引入了嵌套lambda的概念,使得在lambda函数内定义其他lambda函数成为可能。在这种情况下,内层的lambda函数可以访问外层lambda函数的变量。所以如果你想要在C++14中定义其他函数或类,建议将其定义在lambda之外的范围内。

2.8C++14是否支持原始字符串字面量(raw string literals)?如何使用它们?


是的,C++14支持原始字符串字面量(raw string literals)。


原始字符串字面量可以用来表示包含特殊字符(例如转义序列和引号)的字符串,而无需使用转义符号。它们由R"delim(raw_characters)delim"的语法表示,其中delim可以是任何非空字符序列,并且在开始和结束位置上必须匹配。


以下是一个示例:

#include <iostream>
int main() {
    const char* str1 = R"(Hello \n World!)";
    std::cout << str1 << std::endl;  // 输出:Hello \n World!
    const char* str2 = R"###(This is a "quoted" string.)###";
    std::cout << str2 << std::endl;  // 输出:This is a "quoted" string.
    return 0;
}


在上面的示例中,我们使用了原始字符串字面量来创建包含特殊字符的字符串,而不需要使用额外的转义符号。


2.9在C++14中,std::make_unique和std::make_shared这两个函数的作用是什么?


在C++14中,std::make_uniquestd::make_shared是用于创建智能指针的函数模板。

  • std::make_unique:用于创建一个std::unique_ptr对象,它拥有独占所有权的动态分配对象。这个函数接受参数并返回一个std::unique_ptr,它会自动管理内存释放。示例:
auto ptr = std::make_unique<int>(42);
  • std::make_shared:用于创建一个std::shared_ptr对象,它可以被多个指针共享的动态分配对象。这个函数接受参数并返回一个std::shared_ptr,它使用引用计数来管理内存释放。示例:
auto ptr = std::make_shared<int>(42);

这两个函数可以减少手动进行资源管理的工作量,并提供了更安全、更简洁的方式来处理动态分配对象。


2.10C++14引入了统一初始化语法(uniform initialization syntax),具体有哪些变化?


C++14引入了统一初始化语法(uniform initialization syntax),它允许使用一种更统一和一致的方式进行初始化。具体的变化包括以下几个方面:

  1. 初始化列表(initializer list):可以使用花括号 {} 来初始化对象,无论是简单类型还是复杂类型。例如:
    int num{ 42 }; std::vector vec{ 1, 2, 3 };
  2. 自动类型推导:在使用统一初始化语法时,编译器可以自动推导出变量的类型。
    auto value{ 3.14 }; // 推导为 double 类型 auto str{ "Hello" }; // 推导为 const char[6] 类型
  3. 统一构造函数调用语法:通过统一初始化语法,可以直接调用类的构造函数进行对象的创建。
    class MyClass { public: MyClass(int value) { /* 构造函数实现 */ } // ... }; MyClass obj{ 42 }; // 调用构造函数创建对象
  4. 空初始化:可以使用 {}() 进行空初始化,不再需要显式地指定默认值。
    int num{}; // 初始化为0 std::string str{}; // 初始化为空字符串

这些变化使得初始化更加灵活和一致,并且提供了更强大的类型推导能力。注意,在使用统一初始化语法时,要注意类型的精确匹配和可能的隐式转换。


三、C++14 新特性总结


C++14 这一继 C++11 之后的新的 C++ 标准已经被正式批准,正在向ISO 提交,将于年内发布。 C++ 之父 Bjarne Stroustrup 说道,尽管与 C++11 相比,C++14 的改进“有意做的比较小”,但是仍然为用户“带来了极大的方便”,是实现使C++“对新手更为友好”这一目标的步骤之一

在C++ 的时间表中, C++14 按计划是一个小版本,完成制定 C++11 标准的剩余工作,目的是使 C++ 成为一门更清晰、更简单和更快速的语言。新的语言特性留到了未来的 C++17 标准中。

640.jpg


C++14 的主要特性可以分为三个领域:Lambda 函数、constexpr 和类型推导。


3.1Lambda 函数

C++14 的泛型 Lambda 使编写如下语句成为可能:

auto lambda = [](auto x, auto y) {return x + y;};

而另一方面,C++11 要求 Lambda 参数使用具体的类型声明,比如:

auto lambda = [](int x, int y) {return x + y;};

此外,新标准中的 std::move 函数可用于捕获 Lambda 表达式中的变量,这是通过移动对象而非复制或引用对象实现的:

std::unique_ptr ptr(new int(10));
auto lambda = [value = std::move(ptr)] {return *value;};


(1)lambda参数auto

在c++11中,lambda表达式参数需要使用具体的类型声明。

auto f = [] (int a) { return a; }

在c++14中,lambda表达式参数可以直接为auto。

auto f = [] (auto a) { return a; };
cout << f(1) << endl;
cout << f(2.3f) << endl;


3.2constexpr

在 C++11 中,使用 constexpr 声明的函数可以在编译时执行,生成一个值,用在需要常量表达式的地方,比如作为初始化模板的整形参数。C++11 的 constexpr 函数只能包含一个表达式,C++14 放松了这些限制,支持诸如 if 和 switch 等条件语句,支持循环,其中包括基于区间(range)的 for 循环。


(1)变量模板

c++14支持变量模板。

template<class T>
constexpr T pi = T(3.1415926535897932385L);
int main() {
    cout << pi<int> << endl; // 3
    cout << pi<double> << endl; // 3.14159
    return 0;
}


(2)别名模板

c++14支持别名模板。

template<typename T, typename U>
struct A {
    T t;
    U u;
};
template<typename T>
using B = A<T, int>;
int main() {
    B<double> b;
    b.t = 10;
    b.u = 20;
    cout << b.t << endl;
    cout << b.u << endl;
    return 0;
}


(3)constexpr的限制

c++14相较于c++11减少了限制:c++11和c++14中constexpr函数均可以使用递归。

constexpr int factorial(int n) { // C++14 和 C++11均可
    return n <= 1 ? 1 : (n * factorial(n - 1));
}

c++14还可以使用局部变量和循环。

constexpr int factorial(int n) { // C++11中不可,C++14中可以
    int ret = 0;
    for (int i = 0; i < n; ++i) {
        ret += i;
    }
    return ret;
}

c++11中constexpr函数中必须把所有东西放在一个单独的return语句中。

constexpr int func(bool flag) { // C++14 和 C++11均可
    return 0;
}

c++14中constexpr函数没有上述限制。

constexpr int func(bool flag) { // C++11中不可,C++14中可以
    if (flag) return 1;
    else return 0;
}


3.3类型推导

C++11 仅支持 Lambda 函数的类型推导,C++14 对其加以扩展,支持所有函数的返回类型推导:

auto DeducedReturnTypeFunction();


因为 C++14 是强类型语言,有些限制需要考虑:

  • 如果一个函数的实现中有多个返回语句,这些语句一定要推导出同样的类型。
  • 返回类型推导可以用在前向声明中,但是在使用它们之前,翻译单元中必须能够得到函数定义。
  • 返回类型推导可以用在递归函数中,但是递归调用必须以至少一个返回语句作为先导,以便编译器推导出返回类型。


C++14 带来的另一个类型推导方面的改进是 decltype(auto) 语法,它支持使用与 auto 同样的机制计算给定表达式的类型。auto 和 decltype 在 C++11 中就已经出现了,但是它们在推导类型时使用了不同的机制,这可能会产生不同的结果。


C++14 中的其他改变包括可以声明变量模板,支持使用 0b 或 0B 前缀来声明二进制字面常量。InfoQ 已经介绍过 C++14 中可能破坏 C++11 程序的其他小型修改


主流 C++ 编译器对新语言特性的支持正在有条不紊地开发: Clang “完全实现了当前草案的所有内容”; GCC Visual Studio 也对 C++14 的新特性提供了一些支持。


(1)函数返回值类型推导

c++14对函数返回类型推导规则做了优化:

auto func(int i) {  //C++11编译非法,c++14支持auto返回值类型推导
    return i;
}
int main() {
    cout << func(4) << endl;
    return 0;
}

支持函数模块返回值类型推导:

template<typename T>
auto func(T t) { return t; }
int main() {
    cout << func(4) << endl;
    cout << func(3.4) << endl;
    return 0;
}

auto返回值用例:

// 编译失败,多个return语句必须返回相同类型。
auto func(bool flag) {
    if (flag) return 1;
    else return 2.3;
}
// 编译失败,不能返回初始化列表
auto func1() {
    return {1, 2, 3};
}
//虚函数不能返回类型推导
class A{
    virtual auto func() { return 1; }
};
//返回值类型推导可以提前前声明,但使用前必须进行函数定义。
auto f();               // declared, not yet defined
auto f() { return 42; } // defined, return type is int
// 回类型推导可以用在递归函数中,但是递归调用必须以至少一个返回语句作为先导,以便编译器推导出返回类型。
auto sum(int i) {
    if (i == 1)
        return i;              // return int
    else
        return sum(i - 1) + i; // ok
}
int main() {
    cout << f() << endl;
    return 0;
}


3.4C++14其他


(1)[[deprecated]]标记

c++14中增加deprecated标记,修饰类、变量、函数等。编译时产生警告,提醒用户该标记修饰的内容未来可能会被丢弃。

struct [[deprecated]] A { };
int main() {
    A a;
    return 0;
}

(2)二进制字面量与字面量分隔符

c++14引入了二进制字面量和字面量分隔符。

int a = 0b0001'0011'1010;
double b = 3.14'1234'1234'1234;

(3)std::make_unique

c++11中有std::make_shared,c++14增加了std::make_unique。

struct A {};
std::unique_ptr<A> ptr = std::make_unique<A>();

(4)std::shared_timed_mutex与std::shared_lock

c++14通过std::shared_timed_mutex和std::shared_lock来实现读写锁,保证多个线程可以同时读,但是写线程必须独立运行,写操作和读操作不可同时进行,这种情况下才能从shared_mutex中获取性能优势。


c++11 中互斥量

640.jpg

c++14互斥量管理类-锁

  • shared_lock是read lock。搭配std::shared_mutex使用,被锁定后允许其它线程执行同样被shared_lock的代码。
  • lock_gurd和unique_lock是write lock。被锁定后,不允许其它线程执行被share_lock或unique_lock的代码。


通常这样定义:

typedef std::shared_lock<std::shared_mutex> ReadLock;
typedef std::lock_guard<std::shared_mutex> WriteLock;


实现方式:

struct ThreadSafe {
    mutable std::shared_timed_mutex mutex_;
    int value_;
    ThreadSafe() {
        value_ = 0;
    }
    int get() const {
        std::shared_lock<std::shared_timed_mutex> lock(mutex_);
        return value_;
    }
    void increase() {
        std::unique_lock<std::shared_timed_mutex> lock(mutex_);
        value_ += 1;
    }
};


(5)std::integer_sequence

表示一个编译时的整型序列。


(6)std::exchange

以 new_value 替换 obj 的值,并返回 obj 的旧值。注意与std::swap的区别。

vector<int> v{4,5,6,7};
vector<int> x = std::exchange(v, {1,2,3,4});
cout << v.size() << endl;
for (int a : v) {
       cout << a << " ";
}
cout<<endl;
for (int a : x) {
      cout << a << " ";
}

(7)std::quoted

c++14引入std::quoted用于给字符串添加双引号。

string str = "hello world";
cout << str << endl;
cout << std::quoted(str) << endl;
/* 输出
* hello world
* "hello world"
*/


精品文章推荐阅读:

相关文章
|
23天前
|
存储 C++ UED
【实战指南】4步实现C++插件化编程,轻松实现功能定制与扩展
本文介绍了如何通过四步实现C++插件化编程,实现功能定制与扩展。主要内容包括引言、概述、需求分析、设计方案、详细设计、验证和总结。通过动态加载功能模块,实现软件的高度灵活性和可扩展性,支持快速定制和市场变化响应。具体步骤涉及配置文件构建、模块编译、动态库入口实现和主程序加载。验证部分展示了模块加载成功的日志和配置信息。总结中强调了插件化编程的优势及其在多个方面的应用。
185 63
|
19天前
|
编译器 程序员 定位技术
C++ 20新特性之Concepts
在C++ 20之前,我们在编写泛型代码时,模板参数的约束往往通过复杂的SFINAE(Substitution Failure Is Not An Error)策略或繁琐的Traits类来实现。这不仅难以阅读,也非常容易出错,导致很多程序员在提及泛型编程时,总是心有余悸、脊背发凉。 在没有引入Concepts之前,我们只能依靠经验和技巧来解读编译器给出的错误信息,很容易陷入“类型迷路”。这就好比在没有GPS导航的年代,我们依靠复杂的地图和模糊的方向指示去一个陌生的地点,很容易迷路。而Concepts的引入,就像是给C++的模板系统安装了一个GPS导航仪
97 59
|
1月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
46 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
17天前
|
安全 程序员 编译器
【实战经验】17个C++编程常见错误及其解决方案
想必不少程序员都有类似的经历:辛苦敲完项目代码,内心满是对作品品质的自信,然而当静态扫描工具登场时,却揭示出诸多隐藏的警告问题。为了让自己的编程之路更加顺畅,也为了持续精进技艺,我想借此机会汇总分享那些常被我们无意间忽视却又导致警告的编程小细节,以此作为对未来的自我警示和提升。
|
1月前
|
安全 程序员 编译器
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
76 11
|
1月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
51 5
|
29天前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
34 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
1月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
69 2
|
1月前
|
存储 编译器 C++
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
36 2
|
1月前
|
存储 编译器 C++
【C++】面向对象编程的三大特性:深入解析多态机制(三)
【C++】面向对象编程的三大特性:深入解析多态机制