C++17新增特性

C++ core feature!

cplusplus语言特性

If Statements with initializer

带初始化的If语句

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

Constexpr if

在该语句中,条件的值必须是可以按语境转换到bool类型的转换常量表达式。若其值为true,则舍弃false分支语句,否则舍弃true语句。

template<typename T>
void ConstexprIf(T value) {
    if constexpr (std::is_integral_v<T>) {
        std::cout << "is integral" << std::endl;
    } else {
        static_assert(false, "T必须是整型");
    }
}

属性说明符

[[fallthrough]]

指示出从前一标号直落是有意义的,而发生直落给出告警的编译器不应该诊断它。

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

之前编译器会通告没有break的告警,在C++17后使用fallthrough属性就可以消除这个警告了。

[[maybe_unused]]

可以用来消除未使用的函数或变量编译器发出的告警。

[[maybe_unused]] bool unusedVariable = true;
[[maybe_unused]] uint32_t UnusedFunction()
{
    return 0;
}

[[nodiscard]]

如果你的某个函数返回值特别重要,希望使用者不要忽略,可以添加这个属性,在编译的时候如果函数使用者没有使用返回值将会产生一个告警;

[[nodiscard]] bool function()
{
    return true;
}

[[deprecated]]

提示允许使用声明有此属性的名称或实体,但因为一些原因不被鼓励使用,一般用在即将废弃的函数,但是还有老用户使用了这个函数;

[[deprecated("test deprecated")]] bool function()
{
    return true;
}

[[noreturn]]

用来告知函数没有返回值

[[noreturn]] void function() {
    
}

inline变量

inline 变量解决全局变量在头文件中定义之后多处使用产生符号定义错误。

// 以前会报错
// test.h
int test = 10;

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

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

// 重定义错误解决办法
// test.h
extern int test;

// test.cpp
int test = 10;

C++17之后引入的inline变量使得全局变量可以直接在头文件中声明定义。

// test.h
inline int test = 10;

string_view

string_view相对于string来说就是一个只读的stringstring_view的赋值操作的空间成本和时间成本远远胜于stringstring_view的赋值特别像一个指针的赋值,一般来说在以情况使用string_view比较合适。

// 常量string
const string str = "hello world!";
// string_view比较合适
constexpr string_view str = "hello world!";

// 函数参数
void fun(const string &str)
{
    
}
// string_view
void fun(const string_view &str)
{
    
}

any

any是一个可以用于任何类型的单个值的类型安全容器。

std::any Int = 10;
std::any Double = 1.234;
std::any String = std::string_view("hello world!");

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;

std::any a = 1;
if (a.has_value()) {
    std::cout << a.type().name() << std::endl;
}

a.reset();
if (!a.has_value) {
    std::cout << "no value" << std::endl;
}

optional

在返回值是string或者int等出现错误之后非常隐式的表达的地方,使用std::optional就可以帮你解决这一问题;另外就是当对外暴漏了一个结构体,但是里面有些参数是可选项,那optional就派上用场了。

// 1 
[[nodiscard]] std::optional<int> TestOptional1()
{
    if (ok) {
        return 100;
    } else {
        return std::nullopt;
    }
}

[[nodiscard]] std::optional<string> TestOptional2()
{
    if (ok) {
        return "hello world!";
    } else {
        return std::nullopt;
    }
}

// optional
auto res = TestOptional1();
if (res.has_value()) {
    // success
} else {
    // fail
}

auto ret = TestOptional2().value_or("");

// 2
struct MyStruct {
    std::optional<int> width;
    std::optional<int> height;
    int fps{30};
};

void DoSomething(const MyStruct &myStruct)
{
    if (myStruct.width.has_value()) {
        // ...
    }
    
    if (myStruct.height.has_value()) {
        // ...
    }
}

variant

variant是一个类型安全的联合体,variant的一个实例在任意时刻要么保有其一个可选类型之一的值,要么在错误的情况下无值。variant不容许保有引用,数组,或类型void,空variant可以使用std::variant<std::monostate>

struct SystemProxyConfig {
    bool isFile;
};

struct CustomProxyConfig {
    bool isFile;
    std::string pathOrContent;
};

std::variant<SystemProxyConfig, CustomProxyConfig> config;
config = SystemProxyConfig{false};
if (std::get_if<CustomProxyConfig>(&config)) {
    // 成功
    CustomProxyConfig customCfg = std::get<CustomProxyConfig>(config);
} else {
    // 失败
    SystemProxyConfig systemCfg = std::get<SystemProxyConfig>(config);
}

execution

executionc++stl算法库提供了一种算法的执行策略设置,目前支持的策略:

  • sequenced_policy(顺序执行策略)
  • parallel_polixy(并行执行策略)
  • parallel_unsequenced_policy(并行及无序执行策略)
  • unsequenced_policy(无序执行策略)
std::vector<int> testExecution{1,2,3,4,58,23,56,78,55,66,77,9,1,0,45,1111,45,13,57};
auto it1 = std::find(std::exexution::seq, testExecution.begin(), testExecution.end(), 5);
auto it2 = std::find(std::exexution::par, testExecution.begin(), testExecution.end(), 5);
auto it3 = std::find(std::exexution::par_unseq, testExecution.begin(), testExecution.end(), 5);