我一直在使用c++ 11标准中提供的新的auto关键字来处理复杂的模板类型,我相信它就是为这个目的设计的。但我也用它来做以下事情:
auto foo = std::make_shared<Foo>();
更令人怀疑的是:
auto foo = bla(); // where bla() return a shared_ptr<Foo>
我还没有看到很多关于这个话题的讨论。auto似乎被滥用了,因为类型通常是一种文档和完整性检查的形式。你在使用auto方面的界限在哪里,这个新功能的推荐用例是什么?
澄清一下:我并不是在寻求哲学观点;我要求标准委员会对这个关键字的预期使用,可能还会对如何在实践中实现预期使用发表评论。
我认为,当第一眼就不知道如何写类型,但表达式右边的类型很明显时,应该使用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可以使编写代码更容易。
任何语言中的每一个新特性都会被至少某些类型的程序员过度使用。只有通过一些有经验的程序员(不是新手)适度的过度使用,其他有经验的程序员才能学会正确使用的界限。过度使用通常是不好的,但也可能是好的,因为这种过度使用可能会导致功能的改进或更好的功能来取代它。
但如果我写的代码不止几行,比如
auto foo = bla();
where the type is indicated zero times, I might want to change those lines to include types. The first example is great since the type is stated once, and auto saves us from having to write messy templated types twice. Hooray for C++++. But explicitly showing the type zero times, if it's not easily visible in a nearby line, makes me nervous, at least in C++ and its immediate successors. For other languages designed to work at a higher level with more abstraction, polymorphism and genericity, it's fine.
是的,它可能被过度使用而损害可读性。我建议在这样的情况下使用它:确切的类型很长,或者无法表达,或者对可读性不重要,并且变量的寿命很短。例如,迭代器类型通常很长,不重要,所以auto可以工作:
for(auto i = container.begin(); i != container.end(); ++i);
这里的Auto不会影响可读性。
另一个例子是解析器规则类型,它可能很长很复杂。比较:
auto spaces = space & space & space;
with
r_and_t<r_and_t<r_char_t<char>&, r_char_t<char>&>, r_char_t<char>&> spaces =
space & space & space;
另一方面,当类型是已知的并且是简单的,如果显式地声明它会更好:
int i = foo();
而不是
auto i = foo();
我使用auto的一个痛苦经历是在lambda表达式中使用它:
auto i = []() { return 0; };
cout<<"i = "<<i<<endl; // output: 1 !!!
实际上,这里i被解析为int(*)()的函数指针。这只是一个简单的cout,但是想象一下,当它与template一起使用时,会导致什么样的编译/运行时错误。
你应该避免使用这样的表达式,并设置一个合适的返回类型(或受控的decltype())
上述例子的正确用法是:
auto i = []() { return 0; }(); // and now i contains the result of calling the lambda
我使用auto没有任何限制,没有遇到任何问题。有时我甚至把它用于简单的类型,如int。这使得c++对我来说是一种更高级别的语言,并且允许在c++中像在python中一样声明变量。在写完python代码之后,我有时甚至会写例如。
auto i = MyClass();
而不是
MyClass i;
这是我认为auto关键字滥用的一种情况。
Often I don't mind what is the exact type of the object, I'm more interested in its fonctionality, and as function names generally say something about the objects they return, auto does not hurt: in e.g. auto s = mycollection.size(), I can guess that s will be a kind of integer, and in the rare case where I care about the exact type, let's check the function prototype then (I mean, I prefer to have to check when I need the info, rather than a priori when code is written, just in case it would be usefull someday, as in int_type s = mycollection.size()).
关于这个例子,从公认的答案:
for ( auto x = max_size; x > 0; --x )
在我的代码中,在这种情况下我仍然使用auto,如果我想让x是unsigned,那么我使用一个实用函数,命名为say make_unsigned,这清楚地表达了我的担忧:
for ( auto x = make_unsigned(max_size); x > 0; --x )
免责声明:我只是描述我的使用,我没有能力给出建议!
一件容易的事。当你不关心是什么类型时使用它。例如
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;…
在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。”
我指出的一个危险是在引用方面。
如。
MyBigObject& ref_to_big_object= big_object;
auto another_ref = ref_to_big_object; // ?
问题是,在这种情况下,another_ref实际上不是一个引用,它是MyBigObject而不是MyBigObject&。你最终复制了一个大对象而没有意识到它。
如果你直接从一个方法中得到一个引用,你可能不会考虑它实际上是什么。
auto another_ref = function_returning_ref_to_big_object();
你需要"auto&"或者"const auto&"
MyBigObject& ref_to_big_object= big_object;
auto& another_ref = ref_to_big_object;
const auto& yet_another_ref = function_returning_ref_to_big_object();
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++风格要点
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.
TL;DR:见底部的经验法则。
公认的答案包含以下经验法则:
当第一眼不知道如何写类型,但表达式右边的类型很明显时,请使用auto。
但我想说这太严格了。有时我并不关心类型,因为语句已经提供了足够的信息,而无需我花时间去弄清楚类型。这是什么意思呢?考虑一下一些答案中出现的例子:
auto x = f();
是什么使这个例子滥用auto?是我不知道f()的返回类型吗?好吧,如果我知道的话可能会有帮助,但是-这不是我主要关心的。更大的问题是x和f()是没有意义的。如果我们有:
auto nugget = mine_gold();
相反,我通常不关心函数的返回类型是否明显。读这个语句,我知道我在做什么,我对返回值的语义有足够的了解,所以我不觉得我还需要知道它的类型。
所以我的回答是:只要编译器允许,就使用auto,除非:
You feel the variable name together with the initialization / assignment expression do not provide enough information about what the statement is doing.
You feel the variable name together with the initialization / assignment expression provides "misleading" information about what the type should be - i.e., if you had to guess what comes instead of the auto you would be able to make a guess - and it would be wrong, and this false assumption has repercussions later in the code.
You want to force a different type (e.g. a reference).
还有:
在用具体类型替换auto之前,最好给出一个有意义的名称(当然不包含类型名)。
什么汽车?
它告诉编译器根据变量的初始值推断(确定)变量的数据类型。它使用类型演绎。
auto应该用在哪里?
当你对变量的类型不感兴趣时
想要使用它。
当你想要避免非常长和丑陋的typename。
当你不确定自己的类型时。
当你不想在你的代码中看到未初始化的变量。
Auto强制你初始化一个变量,因此你不能忘记做
那
当它不应该使用或缺点的自动
参考它的功能,auto可能会错误地推断类型,1
这种情况是
Std::vector<bool> vec(10,0);
Auto x = vec[2];
Bool y = vec[2];
Std::cout << typeid(x).name() << "\n";
Std::cout << typeid(y).name() << "\n";
g++ 10.2上的输出令人惊讶:
St14_Bit_reference
b
如果你想让你的代码可读&,不应该使用它
对其他人来说是可以理解的。它隐藏了数据类型的可见性
来自读者。