In a previous blog post, I talked about several features included in C++26: specifying a reason to delete a function, placeholder variables with no name, structured binding declaration as a condition, and user-generated static_assert messages. In this post, I will continue exploring the new features that have been already included in the C++26 standard.
#embed
#embed
is a new preprocessor directive that works as #include
but for binary data. Its motivation is pretty simple: developers often need to include resources in their application (encoded text, images, sound, video) etc. but there is no standard or common way to do so. In this context, a resource is any source of data that is accessible during compilation. The #embed
directive is replaced with a comma-separated list of int
literals.
constexpr unsigned char icon_resource[] = { #embed "app.ico" }; constexpr std::vector<unsigned char> sound_resource { #embed "sound.wav" };
There are several parameters that can be specified for #embed
:
limit
: defines an upper limit for the size of the resource to be embeddedprefix
: adds the specified prefix to the embedded resource, but only if it is not emptysuffix
: adds the specified suffix to the embedded resource, but only if it is not emptyif_empty
: replaces the embedded resource with the specified data if the resource is empty
The following are two examples (the first taken from the proposal paper) for using these parameters:
constexpr unsigned char null_terminated_file_data[] = { #embed "might_be_empty.txt" \ prefix(0xEF, 0xBB, 0xBF, ) /* UTF-8 BOM */ \ suffix(,) 0 // always null-terminated }; constexpr unsigned char image[] = { #embed "brush.bmp" if_empty(0xBAADF00D) };
You can read more about #embed
here:
- P1967R14 #embed – a scannable, tooling-friendly binary resource inclusion mechanism
- Resource inclusion
constexpr exceptions
Throwing exceptions in constant evaluated code has not been possible. This makes it hard in some cases to do error handling and report errors. C++26 relaxes constraints on constant expressions, allowing throw statements. Moreover, standard exception classes are now constexpr
, so you can throw them from constant evaluated code.
Here is an example:
constexpr time parse_time(std::string_view input) { auto [correct, hh, mm, ss] = ctre::match<"([01]\d|2[0-3]):([0-5]\d):([0-5]\d)">(input); if (!correct) { throw std::exception("invalid time format"); } return build_time(hh, mm, ss); } int main() { try { constexpr time t1 = parse_time("12:30:59"); // [1] constexpr time t2 = parse_time("12:30:60"); // [2] } catch(std::exception const & e) { } }
Previously, both calls at [1]
and [2]
would have resulted in a compile-time error due to the fact that throwing exceptions from constexpr
functions was not possible. With these changes in C++26:
- call at
[1]
is correct, no errors occur - call at
[2]
produces a compile-time error with the text “invalid time format”
It is important to note that even though throwing exceptions from constant evaluated code is now possible, it is mandatory to catch the possible thrown exceptions. Otherwise, a compile-time error is generated due to the uncaught exception.
constexpr time t1 = parse_time("12:30:59"); // compile time error because exceptions are uncaught
To learn more about this feature see:
Variadic friends
Class templates can grant access to their private and protected members to template parameter classes.
template<typename K, typename V> class D { friend K; friend V; };
However, doing the same for all classes in a parameter pack was not possible.
template <typename... T> class D { friend T...; };
C++26 makes the above snippet possible. Here is another example from the proposal paper, with nested classes:
template<class T> struct C { template<class U> struct Nested; }; template<class... Ts> struct VS { template<class U> friend class C<Ts>::Nested...; // OK };
Variadic friends can be useful in situations such as the CRTP with multiple base classes or granting access to individual member functions using the passkey idiom.
To learn more about this topic see:
You can check the support for this features with different compiler on cppreference: C++26.