在 C++ 中限制“auto”是否违背了它的目的?

bee*_*oop 72 c++ auto c++-concepts c++20

在 C++20 中,我们现在能够将auto关键字限制为仅属于特定类型。因此,如果我有一些如下所示的代码,没有任何限制:

auto something(){
  return 1;
}

int main(){
  const auto x = something();
  return x;
}
Run Code Online (Sandbox Code Playgroud)

这里的变量x被推导为一个int。然而,随着 C++20 的引入,我们现在可以将 约束auto为某种类型,如下所示:

std::integral auto something(){
  return 0;
}

int main(){
  const auto x = something();
  return x;
}
Run Code Online (Sandbox Code Playgroud)

这不是违背了来这里的目的吗auto?如果我真的需要一个std::integral数据类型,我不能完全省略吗auto?我是否完全误解了使用auto

cig*_*ien 79

对推导类型的约束auto并不意味着它需要是特定类型,而是意味着它需要是满足约束的一组类型之一。请注意,约束和类型不是同一件事,并且它们不可互换。

例如,像std::integral 这样的概念将推导类型限制为整数类型,例如intor long,但不是float, or std::string

如果我真的需要一个std::integral数据类型,我不能完全省略吗auto

原则上,我想你可以,但这至少会导致解析困难。例如在声明中

foo f = // ...
Run Code Online (Sandbox Code Playgroud)

foo类型,还是类型的约束?

而在当前语法中,我们有

foo auto f = // ...
Run Code Online (Sandbox Code Playgroud)

毫无疑问,这foo是对 的类型的限制f

  • @MaheeppartapSingh 是的,概念允许程序员使意图更加清晰,这总是好的。还有很多额外的好处,例如,可以通过概念更轻松地捕获错误实例化的函数模板;否则它会要求定义失败,这是令人不快的(产生错误的错误消息,例如) (9认同)
  • 多年来,“auto”给了我一些非常有趣的惊喜。通常,这意味着我在其他地方没有得到完全正确的东西,并且我可以通过约束获得的附加诊断可能会捕获其他棘手的运行时错误或几页几乎难以理解的模板/重载解析注释。 (5认同)

ein*_*ica 37

如果我真的需要一种std::integral数据类型,我不能完全省略 auto 吗?

不,因为std::integral它不是一种类型,而是一个概念,是对类型的约束(或者如果你愿意的话,是一组类型而不是单个类型)。

这不是违背了 auto 的目的吗?

C++11 中的最初目的auto是告诉编译器:无论你推导出什么类型*

对于 C++20,auto有一个扩展的用例 - 以及一个概念,对类型的约束。auto 仍然告诉编译器:无论你推导出什么类型- 但推导也必须遵守约束。

* - 忽略常量、左/右值引用等问题。

  • 有趣的是,_约束_提供了_更多_(或扩展)用例。但我同意:约束给予_更多_权力,因为它给予更多_保证_。:-) (2认同)

NoS*_*tAl 5

概念通常只是将错误移到编译的早期,并使代码更具可读性(因为概念名称是向读者提示您对类型的要求)。

改写:

您很少会以适用于每种类型的方式使用自动变量。

例如:

auto fn(auto x) {
    return x++;
}
Run Code Online (Sandbox Code Playgroud)

如果你这样做,将不起作用:

f(std::string("hello"));
Run Code Online (Sandbox Code Playgroud)

因为您无法递增std::string,所以错误类似于:

error: cannot increment value of type 'std::basic_string<char>'
    return x++;
Run Code Online (Sandbox Code Playgroud)

如果将函数更改为:

auto fn(std::integral auto x) {
    return x++;
}
Run Code Online (Sandbox Code Playgroud)

你会得到类似这样的错误:

:6:6: 注意:候选模板被忽略:不满足约束[with x:auto = std::basic_string] auto fn(std::integral auto x) {

对于一个小例子来说,这并不重要,但对于实际代码,通常 fn 会调用 fn2 调用 fn3... 并且您会在 std/boost/... 实现文件深处得到错误。

因此,通过这种方式,概念将错误转移到第一个函数调用的位置。