
1. Compilers and C++ Standards
As we all know, the C++ standard is constantly evolving, but regardless of the speed of its formulation, there is always a specific date. Before this date, all related documents may be pending or subject to change. The C++ standard is merely a standard; its true implementation in practice requires follow-up and support from relevant compiler vendors. This is often referred to as first-class companies setting standards (though this may not be entirely appropriate here).Currently, mainstream C++ compilers are generally categorized into open-source and closed-source. Overall, there are three major types of compilers: Microsoft’s MSVC, the open-source GCC, and CLANG+LLVM. Of course, in specific cases, some large companies both domestically and internationally have their own compilers that perform quite well, and there are also some niche open-source compilers. For example, the Intel C++ compiler and IBM’s XL compiler, and if anyone remembers, the original Borland C++ compiler should also ring a bell.As mentioned earlier, standards are standards, and compilers are compilers; the two are unified yet divergent, and it is normal for compilers to occasionally make detailed modifications to the standard or include some proprietary features.
2. GCC 15.1 Support for C++26
GCC 15.1 was released on April 25, and overall, this version has undergone a significant upgrade, greatly increasing support for both software and hardware. This includes surprising support for Rust, Cobol, and Fortran. Here, we will only discuss support for C++.GCC 15.1 has nearly completed support for C++23, but there are still some details that need improvement. However, it seems that GDB has not kept pace, which may lead to some issues. In other words, this version’s support for C++23 and C++26 is still experimental (even C++20 is, and GCC 16 will switch to C++20), which everyone should take note of.The support for C++26 in GCC 15.1 mainly includes:1. Pack IndexingThis is mainly used in template programming, especially in metaprogramming, making it much simpler to extract parameters from a template parameter pack. See the code:
// Original method for handling parameters
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);
}
// Using Pack Indexing
template<typename... Types>
void print(Types... args) {
std::cout << args...[0] << '\n';
}
int main() {
print('a', "foo", 42);
}
Note that empty packs cannot be indexed, but it is uncertain whether there will be any handling for this in the future.2. Attributes for Structured BindingsSupport for attributes in structured bindings, see the code:
struct S { int a, b; };
void g(S& s) { auto[ a, b [[gnu::deprecated]] ] = s; }
3. =delete with a ReasonThis is more user-friendly, allowing comments to be added to default-deleted functions, as shown in the code:
void oldfn(char*) = delete("unsafe, use newfn");
void newfn(char*);
void g() { oldfn("bagel"); }
4. Variadic FriendsSupport for variadic friends, which will not be elaborated further, see the code:
template<class... Ts>
class Foo { friend Ts...; };
5. constexpr Placement NewThis is easy to understand, further enhancing the functionality of constexpr to support placement new, see the code:
#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 ConditionThis expands the scope of structured bindings further, including the use of some conditional statements such as if, switch, for, and while, see the code:
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 TypeThis mainly makes the code safer by raising the compilation handling level, changing the compilation of incomplete types from a warning to an error. The following code will produce an error in C++26:
struct S;
void foo(S* p) { delete p; }
9. The Oxford Variadic CommaThis makes the code more rigorous and less ambiguous, standardizing the use of commas, see the code below:
void d_depr(auto...); // deprecated
void d_okay(auto..., ...); // OK
void g_depr(int...); // deprecated
void g_okay(int..., ...); // OK
void h_depr(int x...); // deprecated
void h_okay(int x..., ...); // OK
10. Remove Deprecated Array ComparisonThis completely removes the array comparison that was considered deprecated in the old version of C++20 from the standard.11. EmbedThis feature is somewhat similar to embedding in assembly, but here it refers to the embedding of binary code.12. Redeclaration of Using-DeclarationsThis supports repeated declarations outside of classes. The following code would compile with an error in GCC 14:
enum class E { Smashing, Pumpkins };
void foo() { using E::Smashing; using E::Smashing; using E::Pumpkins; }
13. Bit-Fields and Narrowing ConversionsThis feature further addresses details in the case of bit fields, see the code:
#include <compare>
struct C { long long i : 8; };
void f() { C x{1}, y{2}; x.i <= > y.i; // OK }
14. Overloaded Functions and ConstraintsThis feature clarifies the handling of constraints and overloads, see the code below:
template<bool B>
struct X {
static void f(short) requires B; // #1
static void f(short); // #2
};
void test() {
auto x = &X<true>::f; // OK, deduces void(*)(short), selects #1
auto y = &X<false>::f; // OK, deduces void(*)(short), selects #2
}
15. Fixes and Improvements to Some Issues and Introduction of Important FeaturesThis includes modifications and improvements to C++26, C++23, and C++20, with the most significant enhancement being the long-awaited module std.
3. Conclusion
Ultimately, the implementation of the new C++ standard heavily relies on compiler support. Even if there are some small surprises, overall, the compiler’s support for the new standard requires continuous iteration to be completed. Especially when facing the advancement of significant standards, many foundational libraries may need updates, which increases the difficulty of the compiler’s own updates in terms of both time and workload.But the new will eventually come, and the old will inevitably fade away. Let us strive together!