我一直在使用c++ 11标准中提供的新的auto关键字来处理复杂的模板类型,我相信它就是为这个目的设计的。但我也用它来做以下事情:

auto foo = std::make_shared<Foo>();

更令人怀疑的是:

auto foo = bla(); // where bla() return a shared_ptr<Foo>

我还没有看到很多关于这个话题的讨论。auto似乎被滥用了,因为类型通常是一种文档和完整性检查的形式。你在使用auto方面的界限在哪里,这个新功能的推荐用例是什么?

澄清一下:我并不是在寻求哲学观点;我要求标准委员会对这个关键字的预期使用,可能还会对如何在实践中实现预期使用发表评论。


当前回答

一件容易的事。当你不关心是什么类型时使用它。例如

for (const auto & i : some_container) {
   ...

这里我只关心I是容器里的东西。

它有点像typedefs。

typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;

这里,我不关心h和w是浮点数还是双精度浮点数,只关心它们是任何适合表示高度和权重的类型。

或者考虑

for (auto i = some_container .begin (); ...

这里我只关心它是一个合适的迭代器,支持运算符++(),在这方面有点像鸭子类型。

此外,lambdas的类型不能拼写,因此auto f =[]…是好的风格。另一种方法是强制转换为std::function,但这会带来开销。

我真的无法想象对汽车的“滥用”。我能想到的最接近的是剥夺你自己到一些重要类型的显式转换——但你不会使用auto,你会构造一个所需类型的对象。

如果您可以在不引入副作用的情况下删除代码中的一些冗余,那么这样做一定是好的。

反例(借用别人的回答):

auto i = SomeClass();
for (auto x = make_unsigned (y); ...)

这里我们确实关心类型是什么,所以我们应该写Someclass i;And for(unsigned x = y;…

其他回答

我认为,当第一眼就不知道如何写类型,但表达式右边的类型很明显时,应该使用auto关键字。例如,使用:

my_multi_type::nth_index<2>::type::key_type::composite_key_type::
    key_extractor_tuple::tail_type::head_type::result_type

要在boost::multi_index中获取复合键类型,即使您知道它是int。你不能只写int,因为它将来可能会被改变。在这种情况下我会写auto。

因此,如果auto关键字在特定情况下提高了可读性,那么就使用它。当读者很清楚auto所代表的类型时,可以使用auto。

下面是一些例子:

auto foo = std::make_shared<Foo>();   // obvious
auto foo = bla();                     // unclear. don't know which type `foo` has

const size_t max_size = 100;
for ( auto x = max_size; x > 0; --x ) // unclear. could lead to the errors
                                      // since max_size is unsigned

std::vector<some_class> v;
for ( auto it = v.begin(); it != v.end(); ++it )
                                      // ok, since I know that `it` has an iterator type
                                      // (don't really care which one in this context)

auto与线性代数库(如Eigen或OpenCV)大量使用的表达式模板结合使用可能非常危险。

auto A = Matrix(...);
auto B = Matrix(...);
auto C = A * B; // C is not a matrix. It is a matrix EXPRESSION.
cout << C; // The expression is evaluated and gives the expected result.
... // <code modifying A or B>
cout << C; // The expression is evaluated AGAIN and gives a DIFFERENT result.

由这类错误引起的bug是调试的一大麻烦。一种可能的补救方法是,如果执意要将auto用于从左到右的声明样式,则显式地将结果转换为预期的类型。

auto C = Matrix(A * B); // The expression is now evaluated immediately.

在推断类型有意义的地方使用auto。如果你知道它是一个整数,或者你知道它是一个字符串,只需使用int / std::string等。我不担心“过度使用”一种语言特性,除非它达到荒谬的地步,或者混淆代码。

这只是我的观点。

c++程序的一个主要问题是允许你使用未初始化的变量。这导致了我们讨厌的非确定性程序行为。应该注意的是,现代编译器现在抛出适当的/message警告消息,如果程序累了使用它。

为了说明这一点,考虑下面的c++程序:

int main() {
    int x;
    int y = 0;
    y += x;
}

如果我使用现代编译器(GCC)编译这个程序,它会给出警告。这样的警告可能并非如此 如果我们使用的是真正复杂的产品代码,这是非常明显的。

main.cpp:在函数'int main()'中: Main.cpp:4:8:警告:'x'在此函数中未初始化 (-Wuninitialized) Y += x; ^

================================================================================= 现在如果我们改变我们的程序,使用auto,然后编译,我们得到如下:

int main() {
    auto x;
    auto y = 0;
    y += x;
}

main.cpp:在函数'int main()'中: Main.cpp:2:10:错误:声明'auto x'没有初始化式 汽车x; ^

对于auto,不可能使用未初始化的变量。如果我们开始使用auto,这是我们可以(免费)获得的主要优势。

c++专家Herb Shutter在他的CppCon14演讲中解释了这个概念和其他伟大的现代c++概念:

回归基本!现代c++风格要点

在c++和超越2012的Ask Us Anything小组中,Andrei Alexandrescu、Scott Meyers和Herb Sutter就何时使用和不使用auto进行了一次精彩的交流。跳到25:03分钟进行4分钟的讨论。这三位演讲者都给出了很好的观点,应该记住什么时候不使用auto。

我非常鼓励人们得出自己的结论,但我的结论是在任何地方都要使用auto,除非:

这会影响可读性 关心自动类型转换(例如,从构造函数,赋值,模板中间类型,整数宽度之间的隐式转换)

自由地使用explicit有助于减少对后者的关注,这有助于最大限度地减少前者成为问题的时间。

换句话说,Herb说,“如果你不做X, Y和Z,用auto。了解X, Y和Z是什么,然后在其他地方使用auto。”