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
?
. : PVS-Studio, 2015. , .