为什么使用auto的直接列表初始化被认为是不好或不优先的?

10

我已经养成了使用直接列表初始化编写代码的习惯,如下所示,它更加有效,并且非常有用,可以防止隐式缩小narrowing

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

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

但是当涉及到自动推断类型时,我听说这种写法被认为是不好的或者不被推荐的,为什么呢?


7
花括号周围存在很多缺陷和奇怪的地方。例如,int n; int & r { n }; 曾经是有问题的。而 auto x = { 1, 2 } 转化为 auto y = { 1 } 可能会让人感到意外。基本上,花括号引入了很多不一致性,有些人认为这不值得让读者感到困惑。 - Kerrek SB
2
强烈推荐:Herb Sutter: Almost Always Auto - bolov
2
类型推断正是问题所在。花括号有许多不同的含义,你希望编译器推断右侧你想要做什么,同时也推断左侧的类型。这意味着如果推断右侧的结果出人意料(特别是因为编译器不知道你想要什么,因为没有已知的结果类型),左侧将自动接受结果,并且没有检查会告诉你出现了错误。 - StenSoft
如果标准委员会将元组字面量放入核心语言中,这个问题就不会那么严重了。initializer_list的类型系统处理是一个糟糕的笑话。它的工作方式符合您的期望,除非它不符合。 - Tim Seguine
1个回答

12

这是一个示例,说明使用该语法会失败:

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<Foo>。在这种情况下显然不是我们想要的。如果我们将它改为 auto b = a,那么这样就可以正常工作了。然后,如果我们仍然想使用 auto,但明确声明类型,我们可以将其改为 auto b = Foo{a} 并让编译器省略副本。


1
希望在C++17中能够修复这个问题:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3912.html。 - Anton Savin
4
如果我们仍想使用auto,但显式声明类型,那真的没有意义。auto的整个作用就是避免声明类型。我知道在C#中有一些人会写var x =(string)null;而不是string x = null;,但他们只占极少数,我从未见过任何人真正为编写此类代码进行辩护。我无法想象在C++中有任何有效的论据支持这样做。 - user743382
2
这是几乎总是自动化风格的一部分。由于它包含了一些非常有影响力的人的讨论,因此将其包括在内似乎很相关。 - TartanLlama
2
@TartanLlama 感谢提供的链接。除了评论中没有提到的一件事情,我认为这也是不采用该风格的一个非常强有力的理由,那就是它启用了显式转换运算符。这些转换运算符通常是显式的,有很好的理由,只有在用户明确请求时才应使用它们。例如,给定 struct S { explicit S(int); };S s = 3; 无法编译。而 auto s = S{3}; 则被接受。系统地使用 auto v = T{i}; 语法意味着编译器会少一些机会警告您可能犯的错误。 - user743382
1
@hvd auto x = std::make_unique<SomeTypeName>(bla...); 比重复类型更好。 - M.M
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接