Single-argument static_assert
In C++17 static_assert message was changed to optional, and it’s possible create static_assert without message.
For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
template<typename T> class A { static_assert(std::is_default_constructible_v<T>); }; class X { public: X(int) {} }; int main() { A<X> a; // ERROR: static_assert failed return 0; } |
Nested namespace declarations
Nested namespace declarations allows to declare nested name space without declaring base namespaces.
For example in C++14:
1 2 3 4 5 6 7 |
namespace A { namespace B { namespace C { // ... } } } |
and in C++17:
1 2 3 |
namespace A::B::C { // ... } |
Allow typename in template template parameters
Before C++17 was allowed only keyword class in template template parameter.
So now code may look like this:
1 2 3 4 5 6 7 8 9 10 11 |
template<template<typename> typename X> class A {}; template<typename T> class AA {}; int main() { A<AA> a; return 0; } |
Range-based for takes separate begin/end types
In C++17 range loop was changed from :
1 2 3 4 5 6 7 8 9 10 |
{ auto && __range = for-range-initializer; for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } } |
to :
1 2 3 4 5 6 7 8 9 |
{ auto && __range = for-range-initializer; auto __begin = begin-expr; auto __end = end-expr; for ( ; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } } |
and it’s allows to have begin() and end() iterators , two different types.
And next example can be compiled succesful:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
struct GetEnd { std::string data; struct TheEnd { bool operator()(std::string::iterator i) { return (*i) != ' ' && (*i) != ' '; } }; auto begin() { return data.begin(); } auto end() { return TheEnd(); } }; bool operator!=(std::string::iterator i, GetEnd::TheEnd end) { return end(i); } int main() { for (auto c : GetEnd{ "the end" }) { std::cout << c; } std::cout << std::endl; return 0; } |
TS: p0184r0
Pack expansion in using-declarations
Variadic templates were introduced in C++11, but using declarations didn’t worked with pack expansion. Now it’s possible and quite useful, make code much more clear.
For example overloading lambdas:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
class A {}; class B {}; class C {}; template<typename ... Visitors> struct overload: Visitors ... { overload(Visitors ... visitors) :Visitors{ visitors }... {} using Visitors::operator()...; }; int main() { std::vector<std::variant<A, B, C>> vector = { A{}, B{}, C{} }; for (auto obj : vector) std::visit( overload{ [](A) {}, [](B) {}, [](C) {}, [](auto) {} }, obj ); return 0; } |