9

auto{x}与auto(x)---一位中国小伙为cppreference作出的贡献 - ChebyshevTST

 8 months ago
source link: https://www.cnblogs.com/ChebyshevTST/p/17933558.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

  C++作为一门静态类型语言,是需要程序员声明变量类型的。然而来到了C++11,auto的诞生使得变量声明变得及为方便,尤其是对于比较长的模板类型,auto一定程度上为代码编写者减轻了负担。到了C++23,突然来了个新特性:auto{x}/auto(x),这又是个什么东西,它的motivation又是什么?

  首先这是一个中国小伙为C++23作出的贡献,他是一位在美国工作的engineering,这是他的主页。

3254001-20231228201723813-1408274709.png

到底解决了什么问题?

  来看看这个函数。

void my_erase(auto& x) {
    std::erase(x, x.front());
}

  假如我们传入一个vector类型,vector初始化为{1, 2, 3, 1, 2, 3},然后通过调用std::erase,按照正常想法,函数执行完毕之后vector应该仅仅删掉大小为1首元素。可是事实却并非如此,通过代码运行会发现容器剩下的元素是{2, 3, 1, 3},这里面究竟发生了什么。

_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
reference
front() _GLIBCXX_NOEXCEPT
{
 __glibcxx_requires_nonempty();
 return *begin();
}

  通过源码查看,可以发现front()其实是引用类型,而std::erase本身又调用了std::__remove_if,这也不难让人想出解决问题的办法,也就是做一份拷贝。

void my_erase(auto& x) {
    auto tmp = x.front();
    std::erase(x, tmp);
}

  但是既然都来写Cpp了,我们还可以追求点“洁癖”,我们很多时候并不希望有多余的拷贝,这时候右值就派上了用场。

void my_erase(auto& x) {
    using T = std::decay_t<decltype(x.front())>;
    std::erase(x, T{x.front()});
}

  在进行”类型萃取“之后,我们就可以获取到了容器第一个元素的原始类型,或者叫退化类型,即可以去掉cv限定符还有引用的类型(如果传入的是数组,就会退化为指针)。

  但是到了C++23,在上面这种语境的情况下,auto{x}/auto(x)便可大展拳脚,没再必要进行”类型萃取“。

void my_erase(auto& x) {
    std::erase(x, auto{x.front()});
}

  在现代C++中,auto无疑是宠儿,从C++11到C++14,再到如今的C++23,它随时在发展着,使我们的代码变得更加的简洁和高效。在上面这个例子当中,我们无需进行多余的操作,就能大大地简化代码,或许将来它还能在更多场合发展出优势。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK