C ++言語は常に進化しており、静的アナライザーの開発者として、言語のすべての新しい機能をサポートするためにすべての変更を監視することが重要です。 このレビュー記事では、C ++ 17に登場した最も興味深い革新を読者と共有し、それらを例で示したいと思います。
現在、コンパイラ開発者は新しい標準のサポートを積極的に追加しています。 現在サポートされているものを確認するには、リンクをたどってください。
テンプレートパラメーターの畳み込み(折り畳み式)
まず、リストの折り畳みとは何かについてのいくつかの言葉(一般に、折り畳み、縮小、または累積とも呼ばれます)。
畳み込みは、指定された結合関数をリスト内の連続する要素のペアに適用し、結果を返す関数です。 最も単純な例は、畳み込みを使用したリストアイテムの合計です。
C ++の例:
std::vector<int> lst = { 1, 3, 5, 7 };
int res = std::accumulate(lst.begin(), lst.end(), 0,
[](int a, int b) { return a + b; });
std::cout << res << '\n'; // 16
,
. :
1 + (3 + (5 + (7 + 0)))
( ) ,
. :
(((0 + 1) + 3) + 5) + 7
, .
C++17 . :
(pack op ...) | |
(… op pack) | |
(pack op… op init) | |
(init op… op pack) | |
op – :
+ - * / % ^ & | ~ = < > << >> += -= *= /= %=
^= &= |= <<= >>= == != <= >= && || , .* ->*
pack – , (parameter pack)
init –
, , , :
// C++17
#include <iostream>
template<typename... Args>
auto Sum(Args... args)
{
return (args + ...);
}
int main()
{
std::cout << Sum(1, 2, 3, 4, 5) << '\n'; // 15
return 0;
}
:
Sum constexpr.
, :
// C++17
#include <iostream>
template<typename... Args>
auto Func(Args... args)
{
return (args + ... + 100);
}
int main()
{
std::cout << Func(1, 2, 3, 4, 5) << '\n'; //115
return 0;
}
C++17 , :
// C++14
#include <iostream>
auto Sum()
{
return 0;
}
template<typename Arg, typename... Args>
auto Sum(Arg first, Args... rest)
{
return first + Sum(rest...);
}
int main()
{
std::cout << Sum(1, 2, 3, 4); // 10
return 0;
}
',' (),
pack , . :
// C++17
#include <iostream>
template<typename T, typename... Args>
void PushToVector(std::vector<T>& v, Args&&... args)
{
(v.push_back(std::forward<Args>(args)), ...);
// :
//v.push_back(std::forward<Args_1>(arg1)),
//v.push_back(std::forward<Args_2>(arg2)),
//....
}
int main()
{
std::vector<int> vct;
PushToVector(vct, 1, 4, 5, 8);
return 0;
}
, variadic templates.
template<auto>
auto non-type template . :
// C++17
template<auto n>
void Func() { /* .... */ }
int main()
{
Func<42>(); // int
Func<'c'>(); // char
return 0;
}
non-type template – . , :
// C++14
template<typename Type, Type n>
void Func() { /* .... */ }
int main()
{
Func<int, 42>();
Func<char, 'c'>();
return 0;
}
C++17 , - :
// C++14
auto p = std::pair<int, char>(10, 'c');
std::make_pair, :
// C++14
auto p = std::make_pair(10, 'c');
, . :
#include <tuple>
#include <array>
template<typename T, typename U>
struct S
{
T m_first;
U m_second;
S(T first, U second) : m_first(first), m_second(second) {}
};
int main()
{
// C++14
std::pair<char, int> p1 = { 'c', 42 };
std::tuple<char, int, double> t1 = { 'c', 42, 3.14 };
S<int, char> s1 = { 10, 'c' };
// C++17
std::pair p2 = { 'c', 42 };
std::tuple t2 = { 'c', 42, 3.14 };
S s2 = { 10, 'c' };
return 0;
}
(
deduction guides). , :
// C++17
#include <iostream>
template<typename T, typename U>
struct S
{
T m_first;
U m_second;
};
// deduction guide
template<typename T, typename U>
S(const T &first, const U &second) -> S<T, U>;
int main()
{
S s = { 42, "hello" };
std::cout << s.m_first << s.m_second << '\n';
return 0;
}
deduction guide.
:
deduction guide ,
S ,
deduction guide .,
std::make_pair,
std::make_tuple, .
Constexpr if
C++17 . , . :
// C++17
#include <iostream>
#include <type_traits>
template <typename T>
auto GetValue(T t)
{
if constexpr (std::is_pointer<T>::value)
{
return *t;
}
else
{
return t;
}
}
int main()
{
int v = 10;
std::cout << GetValue(v) << '\n'; // 10
std::cout << GetValue(&v) << '\n'; // 10
return 0;
}
C++17
SFINAE enable_if:
// C++14
template<typename T>
typename std::enable_if<std::is_pointer<T>::value,
std::remove_pointer_t<T>>::type
GetValue(T t)
{
return *t;
}
template<typename T>
typename std::enable_if<!std::is_pointer<T>::value, T>::type
GetValue(T t)
{
return t;
}
int main()
{
int v = 10;
std::cout << GetValue(v) << '\n'; // 10
std::cout << GetValue(&v) << '\n'; // 10
return 0;
}
,
constexpr if .
Constexpr
C++17
constexpr.
constexpr ,
constexpr.
:
constexpr ,
constexpr, .
constexpr :
// ++17
constexpr int Func(int x)
{
auto f = [x]() { return x * x; };
return x + f();
}
int main()
{
constexpr int v = Func(10);
static_assert(v == 110);
return 0;
}
constexpr :
// C++17
int main()
{
constexpr auto squared = [](int x) { return x * x; };
constexpr int s = squared(5);
static_assert(s == 25);
return 0;
}
*this -
-
*this:
class SomeClass
{
public:
int m_x = 0;
void f() const
{
std::cout << m_x << '\n';
}
void g()
{
m_x++;
}
// ++14
void Func()
{
// const *this
auto lambda1 = [self = *this](){ self.f(); };
// non-const *this
auto lambda2 = [self = *this]() mutable { self.g(); };
lambda1();
lambda2();
}
// ++17
void FuncNew()
{
// const *this
auto lambda1 = [*this](){ f(); };
// non-const *this
auto lambda2 = [*this]() mutable { g(); };
lambda1();
lambda2();
}
};
inline
C++17 inline inline . , inline, ( ) .
inline , . :
( , extern .cpp)
header.h:
#ifndef _HEADER_H
#define _HEADER_H
inline int MyVar = 42;
#endif
source1.h:
#include "header.h"
....
MyVar += 10;
source2.h:
#include "header.h"
....
Func(MyVar);
C++17
MyVar extern .cpp .
(Structured bindings)
, , , , Structured bindings Decomposition declaration.
:
// C++17
#include <set>
int main()
{
std::set<int> mySet;
auto[iter, ok] = mySet.insert(42);
....
return 0;
}
insert() pair<iterator, bool>,
iterator bool,
false, (..
mySet).
C++17
std::tie:
// C++14
#include <set>
#include <tuple>
int main()
{
std::set<int> mySet;
std::set<int>::iterator iter;
bool ok;
std::tie(iter, ok) = mySet.insert(42);
....
return 0;
}
,
iter ok .
, :
// C++17
#include <iostream>
int main()
{
int arr[] = { 1, 2, 3, 4 };
auto[a, b, c, d] = arr;
std::cout << a << b << c << d << '\n';
return 0;
}
,
.
// C++17
#include <iostream>
struct S
{
char x{ 'c' };
int y{ 42 };
double z{ 3.14 };
};
int main()
{
S s;
auto[a, b, c] = s;
std::cout << a << ' ' << b << ' ' << c << ' ' << '\n';
return 0;
}
, range-based :
// C++17
#include <iostream>
#include <map>
int main()
{
std::map<int, char> myMap;
....
for (const auto &[key, value] : myMap)
{
std::cout << "key: " << key << ' ';
std::cout << "value: " << value << '\n';
}
return 0;
}
if switch
C++17 if switch :
if (init; condition)
switch(init; condition)
:
if (auto it = m.find(key); it != m.end())
{
....
}
. :
std::map<int, std::string> myMap;
....
if (auto[it, ok] = myMap.insert({ 2, "hello" }); ok)
{
....
}
__has_include
__has_include , .
(P0061R1). optional :
#if __has_include(<optional>)
#include <optional>
#define have_optional 1
#elif __has_include(<experimental/optional>)
#include <experimental/optional>
#define have_optional 1
#define experimental_optional 1
#else
#define have_optional 0
#endif
[[noreturn]],
[[carries_dependency]] [[deprecated]] C++17 3 :
[[fallthrough]], break case (.. case), .
:
// C++17
switch (i)
{
case 10:
f1();
break;
case 20:
f2();
break;
case 30:
f3();
break;
case 40:
f4();
[[fallthrough]]; //
case 50:
f5();
}
[[nodiscard]], , :
// C++17
[[nodiscard]] int Sum(int a, int b)
{
return a + b;
}
int main()
{
Sum(5, 6); // /
return 0;
}
[[nodiscard]] , ,
[[nodiscard]]:
// C++17
struct [[nodiscard]] NoDiscardType
{
char a;
int b;
};
NoDiscardType Func()
{
return {'a', 42};
}
int main()
{
Func(); // /
return 0;
}
[[maybe_unused]], / , , . :
//
[[maybe_unused]] static void SomeUnusedFunc() { .... }
//
void Foo([[maybe_unused]] int a) { .... }
void Func()
{
//
[[maybe_unused]] int someUnusedVar = 42;
....
}
std::byte
std::byte '' .
char,
unsigned char uint8_t.
std::byte , , . ,
std::byte F(const unsigned char *).
<cstddef> :
enum class byte : unsigned char {};
(Dynamic allocation of over-aligned types)
C++11
alignas, . C++17 ,
alignas . , :
// C++17
struct alignas(32) S
{
int a;
char c;
};
int main()
{
S *objects = new S[10];
....
return 0;
}
C++17 , :
, ,
a,
b,
c,
d:
a.b
a->b
a->*b
a(b1, b2, b3)
b @= a
a[b]
a << b << c
a >> b >> c
,
b1,
b2,
b3 - . :
string s =
"but I have heard it works even if you don't believe in it";
s.replace(0, 4, "")
.replace(s.find("even"), 4, "only")
.replace(s.find(" don't"), 6, "");
assert(s == "I have heard it works only if you believe in it");
«The C++ Programming Language, 4th edition», « ». unspecified behavior, C++17, . ,
find .
.. :
obj.F1(subexr1).F2(subexr2).F3(subexr3).F4(subexr4)
subexr1,
subexr2,
subexr3,
subexr4 F1,
F2,
F3,
F4. , .
Filesystem
C++17 .
boost::filesystem, .
std::filesystem.
:
#include <filesystem>
namespace fs = std::filesystem;
fs::path:
fs::path file_path("/dir1/dir2/file.txt");
cout << file_path.parent_path() << '\n'; // "/dir1/dir2"
cout << file_path.filename() << '\n'; // "file.txt"
cout << file_path.extension() << '\n'; // ".txt"
file_path.replace_filename("file2.txt");
file_path.replace_extension(".cpp");
cout << file_path << '\n'; // "/dir1/dir2/file2.cpp"
fs::path dir_path("/dir1");
dir_path.append("dir2/file.txt");
cout << dir_path << '\n'; // "/dir1/dir2/file.txt"
:
//
fs::path current_path = fs::current_path();
//
fs::create_directory("/dir");
//
fs::create_directories("/dir/subdir1/subdir2");
//
if (fs::exists("/dir/subdir1"))
{
cout << "yes\n";
}
//
for (auto &p : fs::directory_iterator(current_path))
{
cout << p.path() << '\n';
}
//
for (auto &p : fs::recursive_directory_iterator(current_path))
{
cout << p.path() << '\n';
}
//
fs::copy("/dir", "/dir_copy");
//
fs::copy("/dir", "/dir_copy", fs::copy_options::recursive);
// ,
fs::remove_all("/dir");
fs::copy_options :
| |
none | , . ( ) |
skip_existing | , . |
overwrite_existing | . |
update_existing | , . |
:
//
if (fs::exists("/dir/file.txt"))
{
cout << "yes\n";
}
//
fs::copy_file("/dir/file.txt", "/dir/file_copy.txt",
fs::copy_options::overwrite_existing);
// ( )
uintmax_t size = fs::file_size("/dir/file.txt");
//
fs::rename("/dir/file.txt", "/dir/file2.txt");
// ,
fs::remove("/dir/file2.txt");
std::filesystem.
.
std::optional
, . , , , , - :
// ++17
std::optional<int> convert(my_data_type arg)
{
....
if (!fail)
{
return result;
}
return {};
}
int main()
{
auto val = convert(data);
if (val.has_value())
{
std::cout << "conversion is ok, ";
std::cout << "val = " << val.value() << '\n';
}
else
{
std::cout << "conversion failed\n";
}
return 0;
}
std::optional value_or,
optional, .
std::any
std::any . ,
std::any int,
float, . :
#include <string>
#include <any>
int main()
{
std::any a = 42;
a = 11.34f;
a = std::string{ "hello" };
return 0;
}
,
std::any , . ,
std::string, ..
std::any .
,
std::any,
std::any_cast. :
#include <iostream>
#include <string>
#include <any>
int main()
{
std::any a = 42;
std::cout << std::any_cast<int>(a) << '\n';
a = 11.34f;
std::cout << std::any_cast<float>(a) << '\n';
a = std::string{ "hello" };
std::cout << std::any_cast<std::string>(a) << '\n';
return 0;
}
std::any_cast , ,
std::bad_any_cast.
type():
#include <any>
int main()
{
std::any a = 42;
std::cout << a.type().name() << '\n'; // "int"
return 0;
}
std::variant
std::variant — ,
union, , . ,
union,
std::variant non-POD .
#include <iostream>
#include <variant>
int main()
{
// int, float char.
std::variant<int, float, char> v;
v = 3.14f;
v = 42;
std::cout << std::get<int>(v);
//std::cout << std::get<float>(v); // std::bad_variant_access
//std::cout << std::get<char>(v); // std::bad_variant_access
//std::cout << std::get<double>(v); // compile-error
return 0;
}
std::variant std::get.
std::bad_variant_access, .
std::get_if,
std::variant , ,
nullptr :
#include <iostream>
#include <variant>
int main()
{
std::variant<int, float, char> v;
v = 42;
auto ptr = std::get_if<int>(&v);
if (ptr != nullptr)
{
std::cout << "int value: " << *ptr << '\n'; // int value: 42
}
return 0;
}
std::variant std::visit:
#include <iostream>
#include <variant>
int main()
{
std::variant<int, float, char> v;
v = 42;
std::visit([](auto& arg)
{
using Type = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<Type, int>)
{
std::cout << "int value: " << arg << '\n';
}
else if constexpr (std::is_same_v<Type, float>)
{
std::cout << "float value: " << arg << '\n';
}
else if constexpr (std::is_same_v<Type, char>)
{
std::cout << "char value: " << arg << '\n';
}
}, v);
return 0;
}
std::string_view
C++17 –
std::string_view, . ,
std::string_view .
std::string_view ,
std::string,
char[N],
char*, 3 :
// C++14
void Func(const char* str);
void Func(const char str[10]);
void Func(const std::string &str);
// C++17
void Func(std::string_view str);
,
const std::string&, std::string_view, , -. , std::string , std::string_view , , .
const string& string_view ,
const string&.
try_emplace insert_or_assign
C++17
std::map std::unordered_map –
try_emplace insert_or_assign.
emplace,
try_emplace «» move-only , . :
// C++17
#include <iostream>
#include <string>
#include <map>
int main()
{
std::string s1("hello");
std::map<int, std::string> myMap;
myMap.emplace(1, "aaa");
myMap.emplace(2, "bbb");
myMap.emplace(3, "ccc");
//std::cout << s1.empty() << '\n'; // 0
//myMap.emplace(3, std::move(s1));
//std::cout << s1.empty() << '\n'; // 1
//std::cout << s1.empty() << '\n'; // 0
//myMap.try_emplace(3, std::move(s1));
//std::cout << s1.empty() << '\n'; // 0
std::cout << s1.empty() << '\n'; // 0
myMap.try_emplace(4, std::move(s1));
std::cout << s1.empty() << '\n'; // 1
return 0;
}
, - ,
myMap,
try_emplace «»
s1,
emplace.
insert_or_assign , , .
std::pair, / , .
operator[], , :
// C++17
#include <iostream>
#include <string>
#include <map>
int main()
{
std::map<int, std::string> m;
m.emplace(1, "aaa");
m.emplace(2, "bbb");
m.emplace(3, "ccc");
auto[it1, inserted1] = m.insert_or_assign(3, "ddd");
std::cout << inserted1 << '\n'; // 0
auto[it2, inserted2] = m.insert_or_assign(4, "eee");
std::cout << inserted2 << '\n'; // 1
return 0;
}
C++17 , ,
operator[].
C++17 , : -, - .
.
C++17 :
namespace ns1::ns2
{
....
}
:
namespace ns1
{
namespace ns2
{
....
}
}
string::data
C++17
std::string data(), :
// ++17
#include <iostream>
int main()
{
std::string str = "hello";
char *p = str.data();
p[0] = 'H';
std::cout << str << '\n'; // Hello
return 0;
}
.
<algorithm>, , . , execution policy, , .
Execution policy 3- :
- std::execution::seq –
- std::execution::par –
- std::execution::par_unseq –
, , :
#include <iostream>
#include <vector>
#include <algorithm>
....
std::for_each(std::execution::par, vct.begin(), vct.end(),
[](auto &e) { e += 42; });
....
, . , ,
.
std::execution::seq – execution policy, , . ,
std::terminate.
, :
std::reduce –
std::accumulate, , . , execution policy. :
....
// vct
std::reduce(std::execution::par, vct.begin(), vct.end())
....
std::transform_reduce – ,
std::reduce.
std::for_each_n –
std::for_each, n . :
....
std::vector<int> vct = { 1, 2, 3, 4, 5 };
std::for_each_n(vct.begin(), 3, [](auto &e) { e *= 10; });
// vct: {10, 20, 30, 4, 5}
....
std::invoke, is_invocable
std::invoke , , . , , ,
operator(), - :
// C++17
#include <iostream>
#include <functional>
int Func(int a, int b)
{
return a + b;
}
struct S
{
void operator() (int a)
{
std::cout << a << '\n';
}
};
int main()
{
std::cout << std::invoke(Func, 10, 20) << '\n'; // 30
std::invoke(S(), 42); // 42
std::invoke([]() { std::cout << "hello\n"; }); // hello
return 0;
}
std::invoke - . C++17
std::is_invocable:
// C++17
#include <iostream>
#include <type_traits>
void Func() { };
int main()
{
std::cout << std::is_invocable<decltype(Func)>::value << '\n'; // 1
std::cout << std::is_invocable<int>::value << '\n'; // 0
return 0;
}
std::to_chars, std::from_chars
C++17
std::to_chars std::from_chars . C C++,
std::to_chars , , :
// C++17
#include <iostream>
#include <charconv>
int main()
{
char arr[128];
auto res1 = std::to_chars(std::begin(arr), std::end(arr), 3.14f);
if (res1.ec != std::errc::value_too_large)
{
std::cout << arr << '\n';
}
float val;
auto res2 = std::from_chars(std::begin(arr), std::end(arr), val);
if (res2.ec != std::errc::invalid_argument &&
res2.ec != std::errc::result_out_of_range)
{
std::cout << arr << '\n';
}
return 0;
}
std::to_chars to_chars_result:
struct to_chars_result
{
char* ptr;
std::errc ec;
};
ptr – + 1
ec –
std::from_chars from_chars_result:
struct from_chars_result
{
const char* ptr;
std::errc ec;
};
ptr – ,
ec –
, , , , -, .. .
std::as_const
std::as_const :
// C++17
#include <utility>
....
MyObject obj{ 42 };
const MyObject& constView = std::as_const(obj);
....
std::size, std::data std::empty
std::begin,
std::end std::size,
std::data std::empty:
// C++17
#include <vector>
int main()
{
std::vector<int> vct = { 3, 2, 5, 1, 7, 6 };
size_t sz = std::size(vct);
bool empty = std::empty(vct);
auto ptr = std::data(vct);
int a1[] = { 1, 2, 3, 4, 5, 6 };
// C-style .
size_t sz2 = std::size(a1);
return 0;
}
std::clamp
C++17
std::clamp(x, low, high), x, [low, high] :
// C++17
#include <iostream>
#include <algorithm>
int main()
{
std::cout << std::clamp(7, 0, 10) << '\n'; // 7
std::cout << std::clamp(7, 0, 5) << '\n'; //5
std::cout << std::clamp(7, 10, 50) << '\n'; //10
return 0;
}
(
std::gcd) (
std::lcm):
// C++17
#include <iostream>
#include <numeric>
int main()
{
std::cout << std::gcd(24, 60) << '\n'; // 12
std::cout << std::lcm(8, 10) << '\n'; // 40
return 0;
}
(Logical operation metafunctions)
C++17
std::conjunction,
std::disjunction std::negation. , , , .
std::conjunction:
// C++17
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
template<typename... Args>
std::enable_if_t<std::conjunction_v<std::is_integral<Args>...>>
Func(Args... args)
{
std::cout << "All types are integral.\n";
}
template<typename... Args>
std::enable_if_t<!std::conjunction_v<std::is_integral<Args>...>>
Func(Args... args)
{
std::cout << "Not all types are integral.\n";
}
int main()
{
Func(42, true); // All types are integral.
Func(42, "hello"); // Not all types are integral.
return 0;
}
, , ,
std::conjunction std::disjunction , .
, :
// C++17
#include <iostream>
enum E
{
A = 0,
B = 1,
C = 2,
First[[deprecated]] = A,
};
namespace[[deprecated]] DeprecatedFeatures
{
void OldFunc() {};
//....
}
int main()
{
//
DeprecatedFeatures::OldFunc();
//
std::cout << E::First << '\n';
return 0;
}
using
using , . (P0028R4):
// C++14
void f()
{
[[rpr::kernel, rpr::target(cpu, gpu)]]
task();
}
// C++17
void f()
{
[[using rpr:kernel, target(cpu, gpu)]]
task();
}
emplace_back
emplace_back , C++17 :
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vct = { 1, 2, 3 };
auto &r = vct.emplace_back(10);
r = 42;
for (const auto &i : vct)
{
std::cout << i << ' ';
}
}
(Searcher functors)
C++17 , , – — – .
std::search:
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
int main()
{
std::string haystack = "Hello, world!";
std::string needle = "world";
//
auto it1 = std::search(haystack.begin(), haystack.end(),
needle.begin(), needle.end());
auto it2 = std::search(haystack.begin(), haystack.end(),
std::default_searcher(needle.begin(), needle.end()));
// -
auto it3 = std::search(haystack.begin(), haystack.end(),
std::boyer_moore_searcher(needle.begin(), needle.end()));
// - -
auto it4 = std::search(haystack.begin(), haystack.end(),
std::boyer_moore_horspool_searcher(needle.begin(), needle.end()));
std::cout << it1 - haystack.begin() << '\n'; // 7
std::cout << it2 - haystack.begin() << '\n'; // 7
std::cout << it3 - haystack.begin() << '\n'; // 7
std::cout << it4 - haystack.begin() << '\n'; // 7
return 0;
}
std::apply
std::apply allable- , . :
#include <iostream>
#include <tuple>
void Func(char x, int y, double z)
{
std::cout << x << y << z << '\n';
}
int main()
{
std::tuple args{ 'c', 42, 3.14 };
std::apply(Func, args);
return 0;
}
(std::make_from_tuple)
C++17 , , .
std::make_from_tuple:
#include <iostream>
#include <tuple>
struct S
{
char m_x;
int m_y;
double m_z;
S(char x, int y, double z) : m_x(x), m_y(y), m_z(z) {}
};
int main()
{
std::tuple args{ 'c', 42, 3.14 };
S s = std::make_from_tuple<S>(args);
std::cout << s.m_x << s.m_y << s.m_z << '\n';
return 0;
}
std::not_fn (Universal negator not_fn)
C++17
std::not_fn, -.
std::not1 std::not2:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
bool LessThan10(int a)
{
return a < 10;
}
int main()
{
std::vector vct = { 1, 6, 3, 8, 14, 42, 2 };
auto n = std::count_if(vct.begin(), vct.end(),
std::not_fn(LessThan10));
std::cout << n << '\n'; // 2
return 0;
}
(Node handle)
++17 . . :
// C++17
#include <map>
#include <string>
int main()
{
std::map<int, std::string> myMap1{ { 1, "aa" },
{ 2, "bb" },
{ 3, "cc" } };
std::map<int, std::string> myMap2{ { 4, "dd" },
{ 5, "ee" },
{ 6, "ff" } };
auto node = myMap1.extract(2);
myMap2.insert(std::move(node));
// myMap1: {{1, "aa"}, {3, "cc"}}
// myMap2: {{2, "bb"}, {4, "dd"}, {5, "ee"}, {6, "ff"}}
return 0;
}
std::extract ,
insert .
C++17 merge,
extract insert:
// C++17
#include <map>
#include <string>
int main()
{
std::map<int, std::string> myMap1{ { 1, "aa" },
{ 2, "bb" },
{ 3, "cc" } };
std::map<int, std::string> myMap2{ { 4, "dd" },
{ 5, "ee" },
{ 6, "ff" } };
myMap1.merge(myMap2);
// myMap1: {{1, "aa"},
// {2, "bb"},
// {3, "cc"},
// {4, "dd"},
// {5, "ee"},
// {6, "ff"}}
// myMap2: {}
return 0;
}
std::map:
// C++17
#include <map>
#include <string>
int main()
{
std::map<int, std::string> myMap{ { 1, "Tommy" },
{ 2, "Peter" },
{ 3, "Andrew" } };
auto node = myMap.extract(2);
node.key() = 42;
myMap.insert(std::move(node));
// myMap: {{1, "Tommy"}, {3, "Andrew"}, {42, "Peter"}};
return 0;
}
C++17 .
static_assert
static_assert :
static_assert(a == 42, "a must be equal to 42");
static_assert(a == 42); //
static_assert ( constant-expression ) ;
static_assert ( constant-expression , string-literal ) ;
std::*_v<T...>
C++17
<type_traits>,
::value, some_trait_v<T>. , some_trait<T>::value, some_trait_v<T>. :
// C++14
static_assert(std::is_integral<T>::value, "Integral required.");
// C++17
static_assert(std::is_integral_v<T>, "Integral required");
std::shared_ptr for arrays
shared_ptr C-.
T[] shared_ptr delete[] . . :
#include <iostream>
#include <memory>
int main()
{
// C++14
//std::shared_ptr<int[]> arr(new int[7],
// std::default_delete<int[]>());
// C++17
std::shared_ptr<int[]> arr(new int[7]);
arr.get()[0] = 1;
arr.get()[1] = 2;
arr.get()[2] = 3;
....
return 0;
}
std::scoped_lock
C++17
scoped_lock, ( lock) , RAII-. :
#include <thread>
#include <mutex>
#include <iostream>
int var;
std::mutex varMtx;
void ThreadFunc()
{
std::scoped_lock lck { varMtx };
var++;
std::cout << std::this_thread::get_id() << ": " << var << '\n';
} // <= varMtx
int main()
{
std::thread t1(ThreadFunc);
std::thread t2(ThreadFunc);
t1.join();
t2.join();
return 0;
}
- .
- register . , auto.
- bool.
- . . C++17 , noexcept.
- std::auto_ptr. std::unique_ptr.
- std::random_shuffle. std::shuffle, , . , std::random_shuffle std::rand, .
, C++17 , , , , C++20.
,
PVS-Studio, , . « », . , C++14 . , , .
V798. . C++17 , , ,
std::execution::par , try...catch.
.
PVS-Studio (Windows/Linux) . C++ « » , . PVS-Studio , « » . .
Proof.
- Changes between C++14 and C++17 DIS.
- Youtube. | C++17.
- Youtube. Nicolai Josuttis. ++17. The Language Features. Part 1, Part 2.
- Herb Sutter. Trip report: Summer ISO C++ standards meeting (Oulu).
- Bartlomiej Filipek. C++ 17 Features.
, : Egor Bredikhin.
C++17