C + + 17 new features

  • preface
  • If Statements with Initializer
  • Constexpr if
  • The inline variable
  • Nested namespaces
  • Property specifier
    • [[FallThrough]] Standard properties
    • [[maybe_unused]] Standard attribute
    • [[nodiscard]] Standard attribute
    • [[deprecated]] Standard attribute
    • [[noretrun]] Standard attributes
  • string_view
  • filesystem
  • any
  • optional
  • variant
  • execution
  • Refer to the link

preface

The previous C++ project used C++14 standard, and considering The Times, C++20 has been basically confirmed. However, since the built-in GCC on the current Linux (uos) does not fully support C++20, so we temporarily consider the new C++17 standard in the new project. And write a complete brief document of the new features that a project might use in C++17


visual studio 2019Compilation parameters need to be added/std:c++17

If Statements with Initializer

If statement with initializer

example

std::map<std::string, int> map;
map["nihao"] = 1;
map["shijie"] = 2;
if (auto ret = map.begin(a); ret ! = map.end()) {
  std::cout << ret->first << ":" << ret->second;
}
Copy the code

Constexpr if

In a CONSTEXPr IF statement, the value of a condition must be a converted constant expression that can be converted to bool contextually. If the value is true, the false branch statement (if present) is discarded, otherwise the true branch statement is discarded.

Often difficult to use for business writing, this is especially useful in template metaprogramming

example

template <typename T>
void TestConstexprIf(T value) {
    if constexpr (std::is_integral_v<T>)
        std::cout << "is integral" << std::endl;
    else
        static_assert(false."T must be an integer.");
}
Copy the code

The inline variable

Inline variables are used to resolve a problem where a global variable is used multiple times after being defined in a header file resulting in a symbol redefinition error

The wrong case

// test.h header file
int test = 10;

// test1.cpp 
void Function1(a) {
  test = 20;
}

// test2.cpp
void Function(a) {
  test = 30;
}


// the above code compilation will generate a redefinition error. Prior to c++17, the solution was to use extern to export global variables

// Solution

// test.h header file
extern int test;

// test.cpp
int test = 10;
Copy the code

After C++17, inline variables were introduced to allow global variables to declare definitions directly in header files

example

inline int test = 10;
Copy the code

Nested namespaces

example

namespace test::test2 {
int i = 0;
}

std::cout << test::test2::i << std::endl;
Copy the code

Property specifier

Attributes for various implementation-defined language extensions (such as GNU and IBM’s __attribute__((…)) ), Microsoft’s language extensions __declSpec (), etc.) provide a unified syntax.

[[FallThrough]] Standard properties

Indicates that a drop from the previous label is intentional, and a compiler that warns when a drop occurs should not diagnose it.

Under the C++17 standard, there is the following code

switch (device.status())
{
case sleep:
   device.wake(a);// fall thru
case ready:
   device.run(a);break;
case bad:
   handle_error(a);break;
}
Copy the code

C++17 could be written like this

switch (device.status())
{
case sleep:
   device.wake(a); [[fallthrough]];case ready:
   device.run(a);break;
case bad:
   handle_error(a);break;
}
Copy the code

The previous code compiler will tell you that there is no break warning, but the fallthrough property in c++17 will eliminate this warning

[[maybe_unused]] Standard attribute

Can be used to eliminate warnings from unused function and variable compilers

example

[[maybe_unused]] bool testUnusedVariable = true;

[[maybe_unused]] 
void TestUnusedFunction(a) {}Copy the code

[[nodiscard]] Standard attribute

If the return value of one of your functions is particularly important, you can add this property, and a warning will be generated if the function user does not use the return value during recompilation

example

[[nodiscard]] bool TestNodiscard(a) {
    return true;
}
Copy the code

[[deprecated]] Standard attribute

Hints allow the use of names or entities that declare this property, but are discouraged for some reason, generally for functions that are about to be deprecated, but are still used by older users

example

// This is not a warning but an error in vs.
[[deprecated("test deprecated")]] bool TestDeprecated(a) {
    return true;
}
Copy the code

[[noretrun]] Standard attributes

Tell the function that it does not return a value

example

[[noreturn]] void TestNoreturn(a) {}Copy the code

string_view

String_view is a read-only string compared to string. The space and time cost of the assignment of string_view is much higher than that of string. Assignment of string_view is particularly like assignment of a pointer, and string_view is generally more appropriate in the following situations

exampel

/ / constant string
const std::string = "hello world";
// string_view is more appropriate
const string_view = "hello world";

// Function arguments
void Function1(const std::string& arg1) {}// string_view is more appropriate
void Function1(string_view arg1) {}Copy the code

filesystem

The experiment/filesystem was used until C++17, when filesystem was officially included in the C++ standard library. Since most people are familiar with filesystem, this is a brief introduction

example

std::filesystem::path path("testpath");
if (std::filesystem::exists(path)) {
  / / there
} else {
  / / does not exist
}
Copy the code

any

Any is a type-safe container that can be used with a single value of any type. If you’ve seen Boost before, you’re probably familiar with the Any class

example

std::any Int = 69;
std::any Double = 69.123;
std::any String = std::string_view("Hello");

std::cout << Int.type().name() << std::endl;
std::cout << Double.type().name() << std::endl;
std::cout << Double.type().name() << std::endl;

std::vector<std::any> anys = { Int, Double, String };
std::cout << std::any_cast<int>(Int) << std::endl;
std::cout << std::any_cast<double>(Double) << std::endl;
std::cout << std::any_cast<std::string_view>(String) << std::endl;

// has_value: indicates whether there is a value
std::any a = 1;
if (a.has_value()) {
  std::cout << a.type().name() << std::endl;// i
}

// reset: Clears the container
a.reset(a);if (a.has_value()) {
  std::cout << "no value\n";// no value
}
Copy the code

optional

If you’re familiar with Boost, you’re probably familiar with optional. It’s most commonly used in cases where you’re returning a string or int that is very implicit. STD :: Optional can help you with this

example

[[nodiscard]]
std::optional<int> TestOptional(a) {
    // Before we might have used return-1 to indicate an error, but now st::optional doesn't need to be too implicit
    if (true) {
        return 9999;
    } else {
        return std::nullopt;
    }
}

[[nodiscard]]
std::optional<std::string> TestOptional2(a) {
    // Before we might have used return-1 to indicate an error, but now st::optional doesn't need to be too implicit
    if (true) {
        return "helloworld";
    } else {
        returnstd::nullopt; }}// optional 
auto result = TestOptional(a);if (result.has_value()) {
  // If there is a value, it indicates success
} else {
  // result has no value indicating failure
}

// This value_OR is used when the return value of TestOptional is nullopt
auto ret = TestOptional2().value_or("");
Copy the code

variant

Variant is used to represent a type-safe union, and an instance of variant either retains a value of one of its optional types at any time or has no value in the case of an error. Variant does not allow you to hold references, arrays, or types of void. A null variant can use STD :: Variant < STD ::monostate>


// variant
struct SystemProxyConfig {
  bool isService;
};

struct CustomProxyConfig {
  bool isFile;
  std::string pathOrContent;
};
std::variant<SystemProxyConfig, CustomProxyConfig> config;
/ / config = CustomProxyConfig {false, "http://192.168.21.161/spiderweb.pac"};
config = SystemProxyConfig{ false };
if (std::get_if<CustomProxyConfig>(&config)) {
  // Type succeeded
  CustomProxyConfig customConfig = std::get<CustomProxyConfig>(config);
} else {
  // Type failed
  SystemProxyConfig systemProxyConfig = std::get<SystemProxyConfig>(config);
  int i = 0;
}
Copy the code

execution

Execution provides a set of execution strategies for the C++STL algorithm library, currently supporting:

  • sequenced_policy(Sequential execution of policies)
  • parallel_policy(Parallel execution strategy)
  • parallel_unsequenced_policy(Parallel and out-of-order execution of policies)
  • unsequenced_policy(Execute policies out of order)

example

    std::vector<int> testExecution{ 1.2.3.4.5.8.19.20 ,30.40.50.0.102.40.10.30.20.1000.32.31.34.45};
    auto it1 = std::find(std::execution::seq, testExecution.begin(), testExecution.end(), 5);
    auto it2 = std::find(std::execution::par, testExecution.begin(), testExecution.end(), 5);
    auto it3 = std::find(std::execution::par_unseq, testExecution.begin(), testExecution.end(), 5);
Copy the code

Refer to the link

cppreference.com

Fallthrough properties