【问题标题】:Why is direct-list-initialization with auto considered bad or not preferred?为什么使用 auto 的直接列表初始化被认为不好或不受欢迎?
【发布时间】:2015-07-05 14:54:50
【问题描述】:

我已经养成了使用下面的直接列表初始化编写代码的习惯,因为它更有效,并且对于防止隐式 narrowing 非常有用:

int i {0};
string s {""};
char c {'a'};
bool b {false};

auto num {100}; // But this??

但是当谈到自动说明符时,我听说这样写它被认为是不好的或不推荐的,这是为什么呢?

【问题讨论】:

  • 花括号周围有很多缺陷和怪异之处。例如。 int n; int & r { n }; 曾经被破坏。而auto x = { 1, 2 } 退化为auto y = { 1 } 可能会令人惊讶。基本上,花括号引入了很多不统一性,有些人认为不值得让读者混淆。
  • 类型推导正是问题所在。花括号有许多不同的含义,您希望编译器在正确的站点上推断出您想要执行的操作,同时在左侧推断出您想要执行的操作的类型。这意味着如果推导在右侧有令人惊讶的结果(特别是因为编译器不知道您想要什么,因为没有已知的结果类型),左侧将自动接受结果并且没有检查会告诉您有问题.
  • 如果标准委员会将元组文字放在核心语言中,这将不是什么大问题。 initializer_list 的类型系统处理是一个糟糕的笑话。它会按照你的预期工作,除非它没有。

标签: c++ c++11 initialization auto type-deduction


【解决方案1】:

以下是使用该语法失败的示例:

struct Foo{};

void eatFoo (const Foo& f){}

int main() {
    Foo a;
    auto b{a};
    eatFoo(b);
}

您可能认为这没问题:b 应该是 Foo 并传递给 eatFoo。不幸的是,这会导致以下编译器错误:

prog.cpp:11:10: error: invalid initialization of reference of type 'const Foo&' from expression of type 'std::initializer_list<Foo>'
  eatFoo(b);

如您所见,b 实际上是std::initializer_list&lt;Foo&gt; 类型。在这种情况下,当然不是我们想要的。如果我们将其更改为auto b = a,则可以正常工作。那么如果我们还想继续使用auto,但是显式声明类型,我们可以把它改成auto b = Foo{a},让编译器删除副本。

【讨论】:

  • 希望这将在 C++17 中得到修复:open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3912.html
  • "那么如果我们仍然想使用auto,但明确说明类型," -- 那真的没有意义。 auto 的重点是避免说明类型。我知道在 C# 中确实有人编写 var x = (string) null; 而不是 string x = null;,但他们只是一小部分,而且我从未见过有人真正捍卫编写这样的代码。我也无法想象在 C++ 中有一个有效的论据。
  • 它是Almost Always Auto style 的一部分。由于它得到了一些非常有影响力的人的讨论,因此将其包括在内似乎是恰当的。
  • @TartanLlama 感谢您的链接。在 cmets 之外没有提到的一件事,在我看来,反对这种风格的一个非常重要的原因是它启用了显式转换运算符。这些转换运算符通常是明确的,有充分的理由,默认情况下不应使用它们,仅当用户明确请求它们时才使用它们。例如,给定struct S { explicit S(int); };S s = 3; 编译失败。 auto s = S{3}; 被接受。系统地使用auto v = T{i}; 语法意味着编译器很少有机会警告您可能出现的错误。
  • @hvd auto x = std::make_unique&lt;SomeTypeName&gt;(bla...); 比重复输入要好
猜你喜欢
  • 1970-01-01
  • 2016-01-20
  • 2011-06-13
  • 1970-01-01
  • 2011-06-15
  • 2021-04-04
  • 2017-05-30
  • 2011-12-17
相关资源
最近更新 更多