开源软件名称:AnthonyCalandra/modern-cpp-features开源软件地址:https://github.com/AnthonyCalandra/modern-cpp-features开源编程语言:Python 100.0%开源软件介绍:C++20/17/14/11OverviewC++20 includes the following new language features:
C++20 includes the following new library features:
C++17 includes the following new language features:
C++17 includes the following new library features:
C++14 includes the following new language features:
C++14 includes the following new library features: C++11 includes the following new language features:
C++11 includes the following new library features:
C++20 Language FeaturesCoroutinesCoroutines are special functions that can have their execution suspended and resumed. To define a coroutine, the An example of a coroutine is a generator function, which yields (i.e. generates) a value at each invocation: generator<int> range(int start, int end) {
while (start < end) {
co_yield start;
start++;
}
// Implicit co_return at the end of this function:
// co_return;
}
for (int n : range(0, 10)) {
std::cout << n << std::endl;
} The above Another example of a coroutine is a task, which is an asynchronous computation that is executed when the task is awaited: task<void> echo(socket s) {
for (;;) {
auto data = co_await s.async_read();
co_await async_write(s, data);
}
// Implicit co_return at the end of this function:
// co_return;
} In this example, the Using a task to lazily evaluate a value: task<int> calculate_meaning_of_life() {
co_return 42;
}
auto meaning_of_life = calculate_meaning_of_life();
// ...
co_await meaning_of_life; // == 42 Note: While these examples illustrate how to use coroutines at a basic level, there is lots more going on when the code is compiled. These examples are not meant to be complete coverage of C++20's coroutines. Since the ConceptsConcepts are named compile-time predicates which constrain types. They take the following form:
where // `T` is not limited by any constraints.
template <typename T>
concept always_satisfied = true;
// Limit `T` to integrals.
template <typename T>
concept integral = std::is_integral_v<T>;
// Limit `T` to both the `integral` constraint and signedness.
template <typename T>
concept signed_integral = integral<T> && std::is_signed_v<T>;
// Limit `T` to both the `integral` constraint and the negation of the `signed_integral` constraint.
template <typename T>
concept unsigned_integral = integral<T> && !signed_integral<T>; There are a variety of syntactic forms for enforcing concepts: // Forms for function parameters:
// `T` is a constrained type template parameter.
template <my_concept T>
void f(T v);
// `T` is a constrained type template parameter.
template <typename T>
requires my_concept<T>
void f(T v);
// `T` is a constrained type template parameter.
template <typename T>
void f(T v) requires my_concept<T>;
// `v` is a constrained deduced parameter.
void f(my_concept auto v);
// `v` is a constrained non-type template parameter.
template <my_concept auto v>
void g();
// Forms for auto-deduced variables:
// `foo` is a constrained auto-deduced value.
my_concept auto foo = ...;
// Forms for lambdas:
// `T` is a constrained type template parameter.
auto f = []<my_concept T> (T v) {
// ...
};
// `T` is a constrained type template parameter.
auto f = []<typename T> requires my_concept<T> (T v) {
// ...
};
// `T` is a constrained type template parameter.
auto f = []<typename T> (T v) requires my_concept<T> {
// ...
};
// `v` is a constrained deduced parameter.
auto f = [](my_concept auto v) {
// ...
};
// `v` is a constrained non-type template parameter.
auto g = []<my_concept auto v> () {
// ...
}; The template <typename T>
requires my_concept<T> // `requires` clause.
void f(T);
template <typename T>
concept callable = requires (T f) { f(); }; // `requires` expression.
template <typename T>
requires requires (T x) { x + x; } // `requires` clause and expression on same line.
T add(T a, T b) {
return a + b;
} Note that the parameter list in a
template <typename T>
concept callable = requires (T f) { f(); };
struct foo {
int foo;
};
struct bar {
using value = int;
value data;
};
struct baz {
using value = int;
value data;
};
// Using SFINAE, enable if `T` is a `baz`.
template <typename T, typename = std::enable_if_t<std::is_same_v<T, baz>>>
struct S {};
template <typename T>
using Ref = T&;
template <typename T>
concept C = requires {
// Requirements on type `T`:
typename T::value; // A) has an inner member named `value`
typename S<T>; // B) must have a valid class template specialization for `S`
typename Ref<T>; // C) must be a valid alias template substitution
};
template <C T>
void g(T a);
g(foo{}); // ERROR: Fails requirement A.
g(bar{}); // ERROR: Fails requirement B.
g(baz{}); // PASS.
template <typename T>
concept C = requires(T x) {
{*x} -> typename T::inner; // the type of the expression `*x` is convertible to `T::inner`
{x + 1} -> std::same_as<int>; // the expression `x + 1` satisfies `std::same_as<decltype((x + 1))>`
{x * 1} -> T; // the type of the expression `x * 1` is convertible to `T`
};
template <typename T>
concept C = requires(T x) {
requires std::same_as<sizeof(x), size_t>;
}; See also: concepts library. Designated initializersC-style designated initializer syntax. Any member fields that are not explicitly listed in the designated initializer list are default-initialized. struct A {
int x;
int y;
int z = 123;
};
A a {.x = 1, .z = 2}; // a.x == 1, a.y == 0, a.z == 2 Template syntax for lambdasUse familiar template syntax in lambda expressions. auto f = []<typename T>(std::vector<T> v) {
// ...
}; Range-based for loop with initializerThis feature simplifies common code patterns, helps keep scopes tight, and offers an elegant solution to a common lifetime problem. for (auto v = std::vector{1, 2, 3}; auto& e : v) {
std::cout << e;
}
// prints "123" likely and unlikely attributesProvides a hint to the optimizer that the labelled statement has a high probability of being executed. switch (n) {
case 1:
// ...
break;
[[likely]] case 2: // n == 2 is considered to be arbitrarily more
// ... // likely than any other value of n
break;
} If one of the likely/unlikely attributes appears after the right parenthesis of an if-statement, it indicates that the branch is likely/unlikely to have its substatement (body) executed. int random = get_random_number_between_x_and_y(0, 3);
if (random > 0) [[likely]] {
// body of if statement
// ...
} It can also be applied to the substatement (body) of an iteration statement. while (unlikely_truthy_condition) [[unlikely]] {
// body of while statement
// ...
} Deprecate implicit capture of thisImplicitly capturing struct int_value {
int n = 0;
auto getter_fn() {
// BAD:
// return [=]() { return n; };
// GOOD:
return [=, *this]() { return n; };
}
}; Class types in non-type template parametersClasses can now be used in non-type template parameters. Objects passed in as template arguments have the type struct foo {
foo() = default;
constexpr foo(int) {}
};
template <foo f>
auto get_foo() {
return f;
}
get_foo(); // uses implicit constructor
get_foo<foo{123}>(); constexpr virtual functionsVirtual functions can now be struct X1 {
virtual int f() const = 0;
};
struct X2: public X1 {
constexpr virtual int f() const { return 2; }
};
struct X3: public X2 {
virtual int f() const { return 3; }
};
struct X4: public X3 {
constexpr virtual int f() const { return 4; }
};
constexpr X4 x4;
x4.f(); // == 4 explicit(bool)Conditionally select at compile-time whether a constructor is made explicit or not. struct foo {
// Specify non-integral types (strings, floats, etc.) require explicit construction.
template <typename T>
explicit(!std::is_integral_v<T>) foo(T) {}
};
foo a = 123; // OK
foo b = "123"; // ERROR: explicit constructor is not a candidate (explicit specifier evaluates to true)
foo c {"123"}; // OK Immediate functionsSimilar to consteval int sqr(int n) {
return n * n;
}
constexpr int r = sqr(100); // OK
int x = 100;
int r2 = sqr(x); // ERROR: the value of 'x' is not usable in a constant expression
// OK if `sqr` were a `constexpr` function using enumBring an enum's members into scope to improve readability. Before: enum class rgba_color_channel { red, green, blue, alpha };
std::string_view to_string(rgba_color_channel channel) {
switch (channel) {
case rgba_color_channel::red: return "red";
case rgba_color_channel::green: return "green";
case rgba_color_channel::blue: return "blue";
case rgba_color_channel::alpha: return "alpha";
}
} After: enum class rgba_color_channel { red, green, blue, alpha };
std::string_view to_string(rgba_color_channel my_channel) {
switch (my_channel) {
using enum rgba_color_channel;
case red: return "red";
case green: return "green";
case blue: return "blue";
case alpha: return "alpha";
}
} Lambda capture of parameter packCapture parameter packs by value: template <typename... Args>
auto f(Args&&... args){
// BY VALUE:
return [...args = std::forward<Args>(args)] {
// ...
};
} Capture parameter packs by reference: template <typename... Args>
auto f(Args&&... args){
// BY REFERENCE:
return [&...args = std::forward<Args>(args)] {
// ...
};
} char8_tProvides a standard type for representing UTF-8 strings. char8_t utf8_str[] = u8"\u0123"; C++20 Library FeaturesConcepts libraryConcepts are also provided by the standard library for building more complicated concepts. Some of these include: Core language concepts:
Comparison concepts:
Object concepts:
Callable concepts:
See also: concepts. Synchronized buffered outputstreamBuffers output operations for the wrapped output stream ensuring synchronization (i.e. no interleaving of output). std::osyncstream{std::cout} << "The value of x is:" << x << std::endl; std::spanA span is a view (i.e. non-owning) of a container providing bounds-checked access to a contiguous group of elements. Since views do not own their elements they are cheap to construct and copy -- a simplified way to think about views is they are holding references to their data. Spans can be dynamically-sized or fixed-sized. void f(std::span<int> ints) {
std::for_each(ints.begin(), ints.end(), [](auto i) {
// ...
});
}
std::vector<int> v = {1, 2, 3};
f(v);
std::array<int, 3> a = {1, 2, 3};
f(a);
// etc. Example: as opposed to maintaining a pointer and length field, a span wraps both of those up in a single container. constexpr size_t LENGTH_ELEMENTS = 3;
int* arr = new int[LENGTH_ELEMENTS]; // arr = {0, 0, 0}
// Fixed-sized span which provides a view of `arr`.
std::span<int, LENGTH_ELEMENTS> span = arr;
span[1] = 1; // arr = {0, 1, 0}
// Dynamic-sized span which provides a view of `arr`.
std::span<int> d_span = arr;
span[0] = 1; // arr = {1, 1, 0} constexpr size_t LENGTH_ELEMENTS = 3;
int* arr = new int[LENGTH_ELEMENTS];
std::span<int, LENGTH_ELEMENTS> span = arr; // OK
std::span<double, LENGTH_ELEMENTS> span2 = arr; // ERROR
std::span<int, 1> span3 = arr; // ERROR Bit operationsC++20 provides a new 全部评论
专题导读
上一篇:CppCon/CppCon2014: Speaker materials from CppCon 2014发布时间:2022-04-21下一篇:microsoft/vscode-cpptools: Official repository for the Microsoft C/C++ extension ...发布时间:2022-04-21热门推荐
热门话题
阅读排行榜
|
请发表评论