C++26 Core Language: Small Improvements
There are more small improvements in the C++26 language, which you should know.
static_assert extension
First, here’s the syntax of static_assert in C++11:
static_assert(compile time predicate, unevaluated string)
With C++26, the string can be a user-defined type having the following properties:
static_assert can now be used with a format string. Here’s a nice example from the proposal p2741r3. I made a complete program out of it.
// static_assert26.cpp
#include <iostream>
#include <format>
template <typename T, auto Expected, unsigned long Size = sizeof(T)>
constexpr bool ensure_size() {
static_assert(sizeof(T) == Expected, "Unexpected sizeof");
return true;
}
struct S {
int _{};
};
int main() {
std::cout << std::boolalpha << "C++11\n";
static_assert(ensure_size<S, 1>());
std::cout << std::boolalpha << "C++26\n";
static_assert(sizeof(S) == 1,
std::format("Unexpected sizeof: expected 1, got {}", sizeof(S)));
std::cout << '\n';
}
The function template ensure_size is defined to take three parameters: a type T, an expected size Expected, and an optional parameter Size which defaults to the size of T. Inside the function, a static_assert statement checks if the size of T is equal to Expected. If the sizes do not match, the compilation will fail with the message “Unexpected sizeof“. The function returns true if the assertion passes.
The program then defines a simple structure S containing a single integer member _. This structure is used to demonstrate the static_assert functionality.
In the main function, the program first prints “C++11” to the console with std::boolalpha to format boolean values as true or false. It then calls static_assert with, which checks if the size of S is 1 byte. Since the size of S is actually larger than 1 byte, this assertion will fail, causing a compilation error.
Next, the program prints “C++26” to the console and uses another static_assert. This time std::format is used. If the size of S is not 1 byte but 4, the compilation will fail.
When you study GCC error messages, you will find three errors. std::format is so far not constexpr.
Pack Indexing
Pack indexing may be your favorite template improvement if you are a template metaprogramming friend.
?
领英推荐
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
?
The following example is based on the proposal P2662R3.
// packIndexing.cpp
#include <iostream>
#include <string>
template <typename... T>
constexpr auto first_plus_last(T... values) -> T...[0] {
return T...[0](values...[0] + values...[sizeof...(values)-1]);
}
int main() {
std::cout << '\n';
using namespace std::string_literals;
std::string hello = first_plus_last("Hello"s, "world"s, "goodbye"s, "World"s);
std::cout << "hello: " << hello << '\n';
constexpr int sum = first_plus_last(1, 2, 10);
std::cout << "sum: " << sum << '\n';
std::cout << '\n';
}
The provided example is a function template that computes the sum of a parameter pack’s first and last elements.
The function is defined as a template that takes a variadic number of parameters of any type?T. The function’s return type is specified using a trailing return type syntax.
The function body returns the sum of the first and last elements of the parameter pack. The expression?values...[0]?accesses the first element and?values...[sizeof...(values)-1]?accesses the last element.
Here’s the output of the program:
delete with reason
With C++26, you can specify a reason for your delete. I assume this will become best practice. The following program shall make this clear.
// deleteReason.cpp
#include <iostream>
void func(double){}
template <typename T>
void func(T) = delete("Only for double");
int main(){
std::cout << '\n';
func(3.14);
func(3.14f);
std::cout << '\n';
}
The function func is overloaded in two ways. The first overload is a regular function that takes a double as its parameter. This function can be called with a double argument without any issues.
The second overload is a function template that can take any type as its parameter. However, this function is explicitly deleted using the = delete specifier with a custom message "Only for double". This means that any instantiation of with a type other than double will result in a compilation error, and the provided message will be displayed.
In the main function, the program calls func with the argument 3.14, which is a double. This call is valid and will invoke the non-template overload of func.
Next, the program attempts to call func with the argument 3.14f, which is a float. Since there is no non-template overload of func that takes a float, the template function would be instantiated. However, because the template function is deleted for any type other than double, this call will result in a compilation error with the message "Only for double".
What is Next?
I will directly jump into the C++26 library in my next blog post.