IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++17的改变 -> 正文阅读

[C++知识库]C++17的改变

原文地址

如初化

{
   if (Foo * ptr = get_foo())
      use(*ptr);
   more_code();
}

不能转为:

{
   {//用这个包含
      QVariant var = getAnswer();
      if (var.isValid())
         use(var);
   }
   more_code();
}

17版本:

{
   if (QVariant var = getAnswer(); var.isValid())use(var);
   more_code();
}

猜语句:

{
   switch (Device dev = get_device(); dev.state())
   {
   case sleep: /*...*/ break;
   case ready: /*...*/ break;
   case bad: /*...*/ break;
   }
}

结构绑定:

tuple<int, string> func();
auto [ i, s ] = func();
use(s, ++i);

编译成:

pair<int, string> func();

auto __tmp = func();//副本
auto & i = get<0>(__tmp);
auto & s = get<1>(__tmp);
//i,s不完全是引用,而是`编译器`的`符号`.

use(s, ++i);

即使auto [i,s] = func();&,也是引用.如:

#include <string>
#include <iostream>

struct Foo
{
   int x = 0;
   std::string str = "world";
   ~Foo() { std::cout << str; }
};

int main()
{
    auto [ i, s ] = Foo();
    std::cout << "你好";
    s = "结构绑定";
}
//编译为
#include <string>
#include <iostream>

struct Foo
{
   int x = 0;
   std::string str = "world";
   ~Foo() { std::cout << str; }
};

int main()
{
    auto __tmp = Foo();
    std::cout << "你好";
    __tmp.str = "结构绑定";
}

输出为你好结构绑定.注意s = "结构绑定";临变量内部修改Foo::str,所以析构器打印结构绑定.&用来应用至隐藏的临时变量.

struct X { int i = 0; };
X makeX();
X x;
auto [ b ] = makeX();
b++;
auto const [ c ] = makeX();
c++;
auto & [ d ] = makeX();
d++;
auto & [ e ] = x;
e++;
auto const & [ f ] = makeX();
f++;
//编译为
struct X { int i = 0; };
X makeX();
X x;

auto __tmp1 = makeX();
__tmp1.i++;
auto const __tmp2 = makeX();
__tmp2.i++; //不能修改常
auto & __tmp3 = makeX(); //非常引用不能绑定临

auto & _tmp3 = x;
x.i++;
auto const & _tmp4 = makeX();
__tmp4.i++; //不能修改常

编译器尽量用get<N>(),所以可直接同用.

struct Foo {
    int x;
    string str;
};

Foo func();
auto [ i, s ] = func();
use(s, ++i);
//编译为
struct Foo {
    int x;
    string str;
};
Foo func();
Foo __tmp = func();
auto & i = __tmp.x;
auto & s = __tmp.str;

use(s, ++i);

实现自己的get(),tuple_size,tuple_element,对默认情况下不行的任何类/构,要实现自己的自定义get<>()并且还要实现tuple_sizetuple_element.

class Foo {
      // ...
   public:
      template <int N> auto & get() /*常?*/ { /*...*/ }
};
//或在类外部取
template<int N> auto & get(Foo /*常?*/ & foo) { /*...*/ }
//...
   
   // 特化tuple_size/element
   // 是的,在标名字空间
namespace std {
  //Foo有多少元素
  template<> struct tuple_size<Foo> { static const int value = 3; }
  //N的类型
  template<int N> struct tuple_element<N, Foo> { using type = 加代码; }
}
   
Foo func();
auto [ i, s ] = func();
use(s, ++i);

数组.

int arr[4] = { /*...*/ };
auto [ a, b, c, d ] = arr;//相当于绑定
auto [ t, u, v ] = std::array<int,3>();
// 映射
for (auto && [key, value] : my_map)
{
    //...
}

如常式.

class Foo {
  int myInt;
  string myString;
public:
  int const & refInt() const
  { return myInt; }
  string const & refString() const
  { return myString; }
};

namespace std
{
   template<> class tuple_size<Foo>
       : public integral_constant<int, 2>
   { };//继承.
   template<int N> class tuple_element<N, Foo>
   {
   public:
      using type =
      conditional_t<N==0,int const &,string const &>;//整,串.
   };
}

template<int N> auto & get(Foo const & foo)
{
  static_assert(0 <= N && N < 2, "仅有2成员");

  if constexpr (N == 0)  // 
     return foo.refInt();
  else if constexpr (N == 1)//
     return foo.refString();
}//常式.

如 常式(式),必须为常式,否则编译不过.
推导:

pair<int, string> is1 = pair(17, "hello");
auto is2 = pair(17, "hello"); // !!pair<int, char const *>
auto is3 = pair(17, string("hello"));
auto is4 = pair(17, "hello"s);

隐式/显式推导.显式:

template<typename T>
struct Thingy
{
  T t;
};

// !! 看这里 !!
Thingy(const char *) -> Thingy<std::string>;
//加上该句
Thingy thing{"串"}; // thing.t是个`标::串`.

元<类 T, 类 U, ...> 构/类...隐式推导类型
元<动>.

template <auto v>
struct integral_constant
{
   static constexpr auto value = v;
};//自动
integral_constant<2048>::value
integral_constant<'a'>::value

折叠表达式

auto x = sum(5, 8);
auto y = sum(a, b, 17, 3.14, ...);
//如何写sum函数.
template <typename... Args>
auto sum(Args&&... args) {
   return (args + ... + 0);
}

嵌套名字空间

namespace A::B::C {
   struct Foo { };
      //...
}

单参输出:

static_assert(sizeof(short) == 2)   

内联变量:

// foo.h
inline int foo = 10;
// foo.h
struct Foo {
   static inline int foo = 10;//内联
};

保证省略复制

// header <mutex>
namespace std
{
   template <typename M>
   struct lock_guard
   {
      explicit lock_guard(M & mutex);
      //不可复制,不可移动
      lock_guard(lock_guard const & ) = delete;
      //...
   }
}

//你代码
lock_guard<mutex> grab_lock(mutex & mtx)
{
   return lock_guard<mutex>(mtx);
}

mutex mtx;

void foo()
{
   auto guard = grab_lock(mtx);
   /*持锁*/
}

[[属性]],直降

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

不丢:

struct SomeInts
{
   [[nodiscard]] bool empty();//不丢.
//不应丢弃返回值.
   void push_back(int);
   //等等
};

void random_fill(SomeInts & container,
      int min, int max, int count)
{
   container.empty(); // 先清理掉
//警告,忽略返回值.
   for (int num : gen_rand(min, max, count))
      container.push_back(num);
}

类/构上:

struct [[nodiscard]] MyError {
  std::string message;
  int code;
};//不丢

MyError divide(int a, int b) {
  if (b == 0) {
    return {"除0", -1};
  }

  std::cout << (a / b) << '\n';

  return {};
}

divide(1, 2);//警告,忽略了不丢返回值.

要小心使用不丢.

[[maybe_unused]] bool res = step1();
//可能未用该res,
assert(res);
step2();
etc();

可能未用函数:

[[maybe_unused]] void f()
{
    /*...*/
}
int main()
{
}

std::string_view串视,标准化现有实践.
假设编写了某种解析器:

Foo parseFoo(std::string const & input);

但是后来一些用户用char *并创建了个string来传递给解析器,所以加(或改为)这个接口:

Foo parseFoo(char const * str);

该接口太有用,用户加至自己的,且最后无尾.

Foo parseFoo(char const * str, int length);

我们又用了自定义的串:

Foo parseFoo(MyString const & str);

如何维护这些接口呢?

Foo parseFoo(std::string_view input);

//不要提供该接口,而是
Foo parseFoo(char const * str, int length)
{
   return parseFoo(string_view(str,length));
}

class MyString {
   //...
   operator string_view() const
   {//符号.串视().
      return string_view(this->data, this->length);
   }
};

2示例

解析xml,不断返回,每个串都是分配,因而用串视.注意,串视不拥有但指向串内存.为引用语义.
标::可选<T>

Foo parseFoo(std::string_view input);
//解析失败怎么办.
std::optional<Foo> parseFoo(std::string_view in);//一个可选搞定.

或者:

if (optional ofoo = parseFoo(str); ofoo)
   use(*ofoo);//这样
optional<int> oi = parseInt(str);
std::cout << oi.value_or(0);

更完美联:std::variant<A,B,C,...>.

struct Stuff
{
   std::variant<int, double, string> data;
};

用法:

void handleData(int i);
void handleData(double d);
void handleData(string const & s);

//...

std::visit([](auto const & val) { handleData(val); }, stuff.data);
//访问(函数+数据)

//也可switch(stuff.data.index())

λ来搞:

struct ThatLambda
{
   void operator()(int const & i) { handleData(i); }
   void operator()(double const & d) { handleData(d); }
   void operator()(string const & s) { handleData(s); }
};

ThatLambda thatLambda;
std::visit(thatLambda, stuff.data);

更多:

if (holds_alternative<int>(data))
   int i = get<int>(data);

// 非双精则抛
double d = get<double>(data);
//
std::variant<Foo, Bar> var;  // 调用 Foo()
//无Foo不编译

Bar bar = makeBar();
var = bar; // 调用~Foo()和Bar(Bar const &)
// (万一Bar(Bar const & b)抛呢?)

var = Foo(); // 调用~Bar()和移动构造器Foo(Foo &&)
// (即使移动不应该抛,万一Foo(Foo && b)抛呢?)

var = someFoo;//调用Foo::operator=(Foo const&)
std::variant<Foo, std::string> foostr;

foostr="hello";//char*不是Foo或string
//但foostr有个std::string

std::any,任何.

std::any v = ...;
if (v.type() == typeid(int)) {
   //整
   int i = any_cast<int>(v);
}

std::any不是模板,运行时更改类型.

std::vector<any> things;

上面可容纳Circles,Squares,Triangles,ints,strings,...等等.
文系:

#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;

void copy_foobar() {//有个特殊的/操作符.
  fs::path dir = "/";
  dir /= "sandbox";
  fs::path p = dir / "foobar.txt";
  fs::path copy = p;
  copy += ".bak";
  fs::copy(p, copy);
  fs::path dir_copy = dir;
  dir_copy += ".bak";
  fs::copy(dir, dir_copy, fs::copy_options::recursive);
}

void display_contents(fs::path const & p) {
  std::cout << p.filename() << "\n";

  if (!fs::is_directory(p))
    return;

  for (auto const & e: fs::directory_iterator{p}) {
    if (fs::is_regular_file(e.status())) {
      std::cout << "  " << e.path().filename()
                << " [" << fs::file_size(e) << " 字节]\n";
    } else if (fs::is_directory(e.status())) {
      std::cout << "  " << e.path().filename() << "\n";
    }
  }
}

大量并行算法(69)个:

123
adjacent_differenceis_heap_untilreplace_copy_if
adjacent_findis_partitionedreplace_if
all_ofis_sortedreverse
any_ofis_sorted_untilreverse_copy
copylexicographical_comparerotate
copy_ifmax_elementrotate_copy
copy_nmergesearch
countmin_elementsearch_n
count_ifminmax_elementset_difference
equalmismatchset_intersection
fillmoveset_symmetric_difference
fill_nnone_ofset_union
findnth_elementsort
find_endpartial_sortstable_partition
find_first_ofpartial_sort_copystable_sort
find_ifpartitionswap_ranges
find_if_notpartition_copytransform
generateremoveuninitialized_copy
generate_nremove_copyuninitialized_copy_n
includesremove_copy_ifuninitialized_fill
inner_productremove_ifuninitialized_fill_n
inplace_mergereplaceunique
is_heapreplace_copyunique_copy

并行使用方法:

std::for_each(std::execution::par, first, last,
    [](auto & x){ process(x); }
);
std::copy(std::execution::par, first, last, output);
std::sort(std::execution::par, first, last);
std::transform(std::execution::par_unseq, xfirst, xlast, yfirst,
    [=](double xi, double yi){ return a * xi + yi; }
);
//在前面加上并行执行.

执行策略,下面的原文不好翻译,要注意:

策略意思
std::execution::seq调用线程不确定有序(线程内重排)
std::execution::par多线程调用,线程内(重排),线程间并行.
std::execution::par_unseq多线程可能向量化,调用间无序,且可能交错.这是放松模式.

技规

std::experimental里面.概念,现在已是标准.

template <RandomAccessIterator T>
auto binarySearch(T first, T second)
{
   //...
}

后面,没啥了.

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:03:37  更:2021-08-09 10:04:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 15:28:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码