c++26新功能——gcc15.1的支持
一、编译器和C++标准
大家都知道,c++标准是不断推陈出新的,但标准的制定无论快慢,总是有一个日期。而在这个日期之前,所有的相关文档都可能是未决的或者理解为都有可能出现变化。而C++标准只是标准,真正的实践于应用之中,需要相关的编译器厂商的跟进和支持。这就是常说的一流的企业做标准(虽然用在这里不是特别贴切)。
目前主流的C++编译器基本是以开闭源划分的。从整体上来看,有三大类编译器即微软的MSVC、开源的GCC和CLANG+LLVM.当然,具体到一些具体的情况,国内外的一些大公司也有自己的编译器而且还做得不错,也有一些开源的小众的编译器。比如前面提到的Intel的C++编译器以及IBM公司的XL编译器等,如果大家有印象,原来的Borland C++编译器应该也听说过。
正如前面所讲,标准是标准,编译器是编译器,二者既统一又有分歧,不时的对标准做一些细节的修改或夹带一些私货这都是正常的。
二、gcc15.1对C++26的支持
GCC15.1已经在4月25日发布,整体上来看,此版本的进行了一次较大的升级,对软硬件的支持都有了很大的增加。包括Rust、Cobol以及Fortran等的支持都有不小的惊喜。此处只讨论对c++的支持。
GCC15.1对c++23的支持几乎已经完成,但仍然有一些细节上待完善的地方,不过,似乎GDB没有跟上,可能会有一些问题。也就是说,这个版本对C++23和c++26的支持仍然是实验性质的(甚至c++20也是,GCC16会切换到C++20),这个大家一定要引起注意。
GCC15.1对c++26的支持主要包括:
1、Pack indexing
它主要应用于模板编程中,特别在元编程中,对于从模板的参数包中取出参数,有了它就变得简单不少,看代码:
//原有方式处理参数
template<typename T, typename... Types>
void print (T t, Types... args)
{std::cout << t << '\n';if constexpr (sizeof...(args) > 0)print (args...);
}int main ()
{print ('a', "foo", 42);
}
//使用Pack Indexing
template<typename... Types>
void print (Types... args)
{std::cout << args...[0] << '\n';
}int main ()
{print ('a', "foo", 42);
}
注意,空包不能索引,不过未来会不会有什么处理,还真不好说。
2、Attributes for structured bindings
支持属性的结构化绑定,见代码:
struct S { int a, b; };void
g (S& s)
{auto [ a, b [[gnu::deprecated]] ] = s;
}
3、=delete with a reason
这个就是更人性化,对默认删除的函数可以增加注释,如代码:
void oldfn(char *) = delete("unsafe, use newfn");
void newfn(char *);void g ()
{oldfn ("bagel");
}
4、Variadic friends
friend对变参的支持,这个不做过多说明,见代码:
template<class... Ts>
class Foo {friend Ts...;
};
5、constexpr placement new
这个好理解,就是对constexpr的功能进一步完善,支持placement new,看代码:
#include <memory>constexpr int foo ()
{std::allocator<int> alloc;auto p = alloc.allocate (16);new (p) int(42);alloc.deallocate (p, 16);return 1;
}int main ()
{constexpr int r = foo ();
}
6、Structured binding declaration as a condition
此项即是地一步扩大的了结构绑定的范围,包括使用一些条件语句,如if,switch,for和while,见代码:
struct S {int a, b;explicit operator bool () const noexcept { return a != b; }
};
void use (int, int);void g (S s)
{if (auto [ a, b ] = s)use (a, b);
}
7、Deleting a pointer to an incomplete type
这项主要是让代码更安全,提高了编译处理的级别,即对不完全类型编译从警告提高到错误,如下的代码在C++26中会报一个错误:
struct S;void foo (S *p)
{delete p;
}
9、The Oxford variadic comma
这个其实就是让代码更严谨一些,不容易产生歧义,规范了逗号的应用,见下的代码:
void d_depr(auto......); // deprecated
void d_okay(auto..., ...); // OKvoid g_depr(int...); // deprecated
void g_okay(int, ...); // OKvoid h_depr(int x...); // deprecated
void h_okay(int x, ...); // OK
10、Remove deprecated array comparison
就是把老版本C++20中认为丢弃的数组比较给彻底扔出了标准
11、embed
这个功能有点类似于汇编的嵌入,不过此处是二进制代码的嵌入。
12、Redeclaration of using-declarations
就是支持在类外进行重复的声明,下面的代码在GCC14中会编译报错:
enum class E { Smashing, Pumpkins };
void foo() {using E::Smashing;using E::Smashing;using E::Pumpkins;
}
13、Bit-fields and narrowing conversions
此功能是进一步处理位字段情况下的细节,见代码:
#include <compare>struct C {long long i : 8;
};void f() {C x{1}, y{2};x.i <=> y.i; // OK
}
14、Overloaded functions and constraints
这个功能其实就是将约束和重载进行更清晰的处理,见下面的代码:
template<bool B> struct X {static void f(short) requires B; // #1static void f(short); // #2
};
void test() {auto x = &X<true>::f; // OK, deduces void(*)(short), selects #1auto y = &X<false>::f; // OK, deduces void(*)(short), selects #2
}
15、对一些问题的修复和细节的完善以及对一些重要功能的引入
这其中包括C++26、C++23和c++20等的修改完善,最重要的是极大的增强了开发者一直期待的module std;
三、总结
其实C++新标准的落地,最重要的还是看编译器的支持。即使会有一些小的惊喜,但整体上,编译器对新标准的支持需要不断的迭代才可能完成。特别是面临一些重大标准的推进,可能有较多的基础库需要更新,这就使得编译器自身的更新迭代无论从时间还是工作量上都增加不少的难度。
但新的终究会来,老的终将故去。与诸君共勉!