使用C++ 11 auto关键字多少钱?

Ala*_*ing 210 c++ types type-inference auto c++11

我一直在使用autoC++ 11标准中提供的新关键字来处理复杂模板类型,这是我认为它的设计目标.但我也用它来做:

auto foo = std::make_shared<Foo>();
Run Code Online (Sandbox Code Playgroud)

更加怀疑的是:

auto foo = bla(); // where bla() return a shared_ptr<Foo>
Run Code Online (Sandbox Code Playgroud)

我没有看到很多关于这个话题的讨论.似乎auto可能过度使用,因为类型通常是文档和健全性检查的一种形式.您在哪里绘制使用线auto以及此新功能的推荐用例是什么?

澄清:我不是要求哲学观点; 我要求标准委员会对该关键字的预期用途,可能还有关于如何在实践中实现该预期用途的评论.

旁注:此问题已移至SE.Programmers,然后返回Stack Overflow.关于这一点的讨论可以在这个元问题中找到.

Kir*_*sky 124

我认为auto只要很难说第一眼看到如何写类型就应该使用关键字,但表达式右侧的类型是显而易见的.例如,使用:

my_multi_type::nth_index<2>::type::key_type::composite_key_type::
    key_extractor_tuple::tail_type::head_type::result_type
Run Code Online (Sandbox Code Playgroud)

获取复合键类型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)
Run Code Online (Sandbox Code Playgroud)

  • 无论C++顽固分子是否愿意,C++ 0x都会吸引那些从未使用过C++的人.那些将在整个地方使用汽车. (43认同)
  • 这似乎不是一个非常好的建议.您多久不知道对象的类型?(在模板之外,也就是说.)如果你不知道他们输入,请查找,不要懒惰并使用自动. (17认同)
  • @Paul:经常你只知道或者只需要知道类型中最重要的部分,例如它是一个迭代器,但你不知道也不关心它是否是向量的迭代器或链接的迭代器列表; 在这些情况下,你真的不想花时间和屏幕空间试图弄清楚如何写下类型. (9认同)
  • @LuisMachuca我的回答是一种说不出话来的方式,说一个教科书中不良变量和函数命名的例子,并指责它在类型推断上缺乏可读性是不诚实的. (8认同)
  • @ R.MartinhoFernandes - 不,唯一明确的是_whatever_`bla()`返回你将它赋予`foo`. (6认同)
  • @Paul,我添加了此类样本。我知道如何在不使用`auto`的情况下写这种类型(我做到了),但是写这种类型不会增加代码的可读性。 (2认同)
  • @Lex Fridman,那是一样的.如果对于读者来说显而易见的是`auto`背后是什么类型,你可以写`auto`. (2认同)

Jon*_*rdy 60

尽可能auto在任何地方使用- 特别是const auto这样可以减少副作用.除了明显的情况外,您不必担心类型,但它们仍然会为您进行静态验证,并且您可以避免重复.在auto不可行的地方,您可以使用decltype语义表达类型作为基于表达式的契约.您的代码看起来会有所不同,但这将是一个积极的变化.

  • 我会特别说'const auto&' (11认同)
  • @SubMachine:除非您使用记事本而不是某些适当的 IDE,否则您不必自己推断出类型 (5认同)
  • 听起来不错.如果我能用于decltype,也可以+2. (3认同)
  • 到处使用auto会使代码的可读性和调试难度降低,因为在阅读代码时必须自己推断类型。 (3认同)
  • @Young我并不是说你不应该使用它,我说你应该对此保持聪明 - 在你认为它可以增强代码可读性的地方使用 auto ,并在它掩盖代码意图的地方避免使用它。“正确的”IDE 并不总是可供您使用,即使可以使用,将鼠标悬停在变量上以获取其类型也比仅将类型视为代码的一部分更不方便。 (3认同)
  • 在复杂情况下更好地使用`auto &amp;&amp;`http://edmundv.home.xs4all.nl/blog/2014/01/28/use-auto-and-and-for-range-based-for-loops/ (2认同)
  • @KindDragon:这是一个很好的经验法则,但是我更喜欢使用const auto&或const auto,除非我明确想要变异或移动。 (2认同)
  • “*随时随地使用汽车*”。这是否意味着我应该写 `auto str = std::string();` 而不是 `std::string str;`? (2认同)
  • @Young 正式的代码审查中是否存在智能感知? (2认同)

spr*_*aff 48

简单.当你不在乎什么类型时使用它.例如

for (const auto & i : some_container) {
   ...
Run Code Online (Sandbox Code Playgroud)

我所关心的就是i容器中的任何东西.

这有点像typedef.

typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;
Run Code Online (Sandbox Code Playgroud)

在这里,我不在乎是否hw是浮动还是双打,只是他们是什么类型适合于表达高度和重量.

或考虑一下

for (auto i = some_container .begin (); ...
Run Code Online (Sandbox Code Playgroud)

这里我关心的是它是一个合适的迭代器,支持operator++(),就像在这方面的鸭子打字.

lambda的类型也不能拼写,所以auto f = []...风格也很好.替代方案是铸造,std::function但随之而来的是开销.

我无法想象一个"虐待" auto.我能想象到的最接近的是剥夺了自己对某种重要类型的显式转换 - 但你不会使用auto它,你构建了一个所需类型的对象.

如果你可以删除代码中的一些冗余而不引入副作用,那么这样做一定很好.

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

auto i = SomeClass();
for (auto x = make_unsigned (y); ...)
Run Code Online (Sandbox Code Playgroud)

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

  • 我是说你是否使用引用与你是否使用auto是正交的.我会编辑它以添加引用,因为不可否认,这通常是人们想要做的,但它与手头的主题完全无关. (5认同)
  • 并不总是,但你可能想要参考.所以呢?这与*auto`没什么关系*. (2认同)

Dar*_*enW 43

去吧.使用auto它可以使编写代码更容易.

任何语言的每个新功能都会被至少某些类型的程序员过度使用.只有通过一些有经验的程序员(而不是新手)适度过度使用,其他有经验的程序员才能学会正确使用的界限.极度过度使用通常很糟糕,但可能会很好,因为这种过度使用可能会导致功能的改进或更换功能的更好功能.

但是,如果我正在使用多行代码来处理代码

auto foo = bla();
Run Code Online (Sandbox Code Playgroud)

如果类型指示为零次,我可能想要更改这些行以包括类型.第一个例子很棒,因为类型被陈述一次,并且使auto我们不必两次编写凌乱的模板类型.Hooray for C++++.但明确显示类型零次,如果它在附近的行中不容易看到,会让我感到紧张,至少在C++及其直接后继者中.对于其他设计为在更高层次上工作且具有更多抽象,多态性和通用性的语言,它很好.

  • 当“using”语句是长类型名称的别名时,为什么人们总是用“长类型名称”来证明“auto”的合理性?使用别名 = aVeryLongName (2认同)

Gen*_*yev 36

是的,它可能被过度使用而不利于可读性.我建议在确切类型很长,或者说不可知,或者对可读性不重要的上下文中使用它,并且变量是短暂的.例如,迭代器类型通常很长并且不重要,因此auto可以工作:

   for(auto i = container.begin(); i != container.end(); ++i);
Run Code Online (Sandbox Code Playgroud)

auto 这里不会伤害可读性.

另一个例子是解析器规则类型,它可以很长并且是复杂的.相比:

   auto spaces = space & space & space;
Run Code Online (Sandbox Code Playgroud)

r_and_t<r_and_t<r_char_t<char>&, r_char_t<char>&>, r_char_t<char>&> spaces = 
   space & space & space;
Run Code Online (Sandbox Code Playgroud)

另一方面,当类型已知并且很简单时,如果明确说明它会更好:

int i = foo();
Run Code Online (Sandbox Code Playgroud)

而不是

auto i = foo();
Run Code Online (Sandbox Code Playgroud)

  • @geotavros:或者你可以看到`space`是什么类型,并搜索它.无论如何,这是更有用的信息......毕竟,问题不是"这个新变量是什么类型"而是"空间和空间和空间是什么意思?" 表达式的实际类型只是噪音. (7认同)
  • @geotavros:和`r_and_t <r_and_t <r_char_t <char>&,r_char_t <char>&>,r_char_t <char>&>`有吗? (6认同)
  • @Fred:任何时候你的边界不是`begin()`和`end()`,或者你的步长不是一个,或者你在循环时修改容器,基于范围的for语句赢了'帮你. (3认同)
  • 当然,在语言中使用基于范围的for循环会让你的第一个例子变得不那么令人兴奋.8V) (2认同)

Sea*_*ean 36

C++和2012年之后的Ask Us Anything小组中,Andrei Alexandrescu,Scott Meyers和Herb Sutter之间auto进行了一次精彩的交流,谈论何时使用而不使用.跳到分钟25:03进行4分钟的讨论.所有三个扬声器都提供了优秀的要点,在使用时应牢记这一点auto.

我强烈鼓励人们得出自己的结论,但我的收获是到处使用auto,除非:

  1. 它伤害了可读性
  2. 关注自动类型转换(例如,来自构造函数,赋值,模板中间类型,整数宽度之间的隐式转换)

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

重写赫伯所说的,"如果你不做X,Y和Z,请使用auto.了解X,Y和Z是什么,然后auto在其他地方使用."

  • 可能也值得链接到"几乎总是自动" - http://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/ (3认同)

mor*_*paj 18

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.
Run Code Online (Sandbox Code Playgroud)

由此类错误引起的错误是调试的主要难题.一种可能的补救方法是,如果您希望使用auto来实现从左到右的声明样式,那么将结果显式地转换为期望的类型.

auto C = Matrix(A * B); // The expression is now evaluated immediately.
Run Code Online (Sandbox Code Playgroud)

  • 一开始这似乎是奇怪的行为。如果我将两个矩阵相乘,即使操作是惰性的,我也不希望它可以重新评估,我希望它在初始评估后保持其评估状态。如果你想在不修改原始参数的情况下更改参数,那么你最终是否必须重建表达式?或者它是为流处理类型的情况而设计的,其中原始参数不断变化但过程保持不变? (2认同)
  • 无论“A*B”表达式是否被复制到“auto”变量或其他变量中,您描述的行为仍然存在。 (2认同)
  • 我还发现了像“for (auto o : vecContainer)”这样的代码,其中“o”是一个每次都会被复制的重对象。我的建议是将其用于最初的用途,即模板(具有困难的推导指南)和费力的 typedef。即使如此,您也必须小心区分 auto 和 auto&amp;。 (2认同)

raf*_*fak 10

我使用autowihout限制,并没有遇到任何问题.我有时甚至最终会将它用于简单的类型int.这使得c ++成为我的高级语言,并允许在c ++中声明变量,就像在python中一样.编写python代码后,我甚至有时会写例如

auto i = MyClass();
Run Code Online (Sandbox Code Playgroud)

代替

MyClass i;
Run Code Online (Sandbox Code Playgroud)

这是一个案例,我会说这是滥用auto关键字.

通常我不介意对象的确切类型是什么,我对它的功能更感兴趣,并且因为函数名称通常会说出它们返回的对象,auto不会受到伤害:例如auto s = mycollection.size(),我可以猜测它s会是一种整数,在极少数情况下,我关心确切的类型,让我们检查函数原型然后(我的意思是,我更愿意检查何时需要信息,而不是在编写代码时的先验,只是如果有一天它将是有用的,如在int_type s = mycollection.size()).

关于这个例子来自公认的答案:

for ( auto x = max_size; x > 0; --x )
Run Code Online (Sandbox Code Playgroud)

在我的代码中,我仍然auto在这种情况下使用,如果我想要x无符号,那么我使用一个名为say的实用函数make_unsigned,它清楚地表达了我的担忧:

for ( auto x = make_unsigned(max_size); x > 0; --x )
Run Code Online (Sandbox Code Playgroud)

免责声明:我只是描述我的使用,我不能提供建议!

  • 后续行动:见:http://herbsutter.com/2013/06/13/gotw-93-solution-auto-variables-part-2/.建议使用例如`as_unsigned`,甚至`auto w = widget {};`. (3认同)