所以我理解var
在 C# 中使用是有意义的,因为你有编译器派生的匿名类型。C++ 似乎没有这个特性(除非我错了),那么有一个auto
关键字有什么意义呢?
(这有点酷,与 C# 不同,auto
它确实适用于成员/全局变量,我想这很酷,但似乎不足以证明它的存在)。
auto
当涉及到泛型编程和为程序员节省一些打字时,它有很多用途。
例如,考虑这个。你宁愿输入:
std::unique_ptr<name::long_type::goes_here> g =
std::make_unique<name::long_type::goes_here>(1,2,3,4)
或者:
auto g = std::make_unique<name::long_type::goes_here>(1,2,3,4)
是的,它们都很长,但我们知道返回类型并再次指定它有点麻烦。这也适用于迭代器:
for(auto i = vec.begin(); ...)
与:
for(std::vector<type>::iterator i = vev.begin(); ...)
它在泛型编程中的用途也是确定函数的返回类型,或者如果您正在执行一些您不知道类型的泛型算法。
例如,考虑一个非常基本的例子。
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
这允许编译器找出添加操作的类型,而不是我们自己试图找出它。请注意,在 C++14 中,您可以省略尾随返回类型。它在泛型编程中的使用也不止于此。如果我们想使用任何类型的容器作为算法的包装函数,我们可以使用auto
它来帮助我们。例如:
template<class Cont>
void my_sort(Cont&& cont) {
using std::begin;
auto first = begin(std::forward<Cont>(cont));
// work with the iterators here
}
在未来 (C++14) 中,auto 也可用于制作多态 lambda,例如:
[](auto a) { return a + 4; }
这也很有用。
auto
在 C++中有许多用途
匿名函数对象,又名闭包,又名 lambda 实例。 auto
是存储它们的唯一方法。类型也可以从这些类型中派生出来,并在它们的背面产生类型,无穷无尽。
C++ 可以具有相当复杂的类型,例如将非变异迭代器的类型转换为使用自定义分配器和散列函数的无序映射。 typedef
可以减轻这种情况,但是m.begin()
具有特定名称的 a 类型并不能提供太多信息:foo_iterator it =
与 一样有意义auto foo_iterator =
,并且在auto
其他地方不需要样板。
返回类型推导使用auto
关键字,这是在template
没有大量特征样板的情况下执行某些功能所必需的。消除样板是一个常见的主题:C++ 强大的类型系统意味着类型可以携带大量信息,并且在每次使用时对其进行编码可能会适得其反。
在一些ducktypetemplate
代码中,推断变量类型的工作与编码变量值的工作大致相同,并且在结构上几乎相同,有时是字面意思:decltype(long expression) x = long expression;
. auto
消除了这种重复。
最后在 C++1y 中,类型推导 lambdasauto
用来表示参数是推导的。有点轻template
。将其扩展到非 lambdas 的讨论也在 skunkworks 中。
这是一个真实的例子,我不能,不使用 auto
我试图在 C++ 中执行 switch 类型语句,其中返回类型是特定于实现的,并且不能轻易声明。因此,使用“自动”可能是解决类型查找地图声明的正确方法。
auto foo = boost::bind(&VegaFactory::load_commodity_one_leg,this,conn,_1);
std::map<std::string,decltype(foo)> methods;
methods.insert(std::make_pair("FOO",commodityOneLeg));
auto f = methods.find(bar);
// Call f here
C++ 确实有“匿名”类型——您不能通过名称引用类型,因为您无法使用该名称。甚至在 C++11 和 lambda 之前就是这种情况。考虑以下代码:
class foo {
class bar {
public:
void baz() { }
};
public:
static bar func() { return bar(); }
};
foo::func().baz(); // OK, only the name "bar" is private
??? a = foo::func(); // Umm...
auto b = foo::func(); b.baz(); // Hooray!
即使实际上没有在私有范围内声明,库在其 API 中保留未指定的某些类型通常也很有用 - 特别是在大量使用表达式模板或其他模板元编程时,其中类型名称可以任意长且所有嵌套模板参数. 甚至标准本身也这样做——例如,std::bind
规范没有定义结果类型。
句法糖
我宁愿说
auto i = mapping.begin();
超过
std::map<int, int>::iterator i = mapping.begin();
值得一读 Herb Sutter 的文章几乎总是自动,以了解为什么值得auto
在显式类型上使用它的一些很好的例子。主要优点是减少了输入,并且在底层类型发生变化时提供了额外的安全性。我最喜欢的例子之一是它如何减少重复。如果您在堆栈上分配,那么您将使用:
MyClass c(param);
但是,如果你想在你需要的堆上创建:
MyClass* c=new MyClass(param);
所以你不得不复制MyClass
,但是 RHS 已经强制变量成为一个MyClass
指针,所以你可以使用它来代替:
auto c=new MyClass(param);
如果您想将其声明为unique_ptr
then 之前您将需要:
unique_ptr<MyClass> c=make_unique<MyClass>(param);
可以缩写为:
auto c=make_unique<MyClass>(param);
在 C++ 中,auto 关键字提供了一种类型推导机制。例如,
auto i = expressions;
auto 关键字告诉编译器从赋值运算符右侧的表达式中确定变量 i 的类型。
因此,如果表达式的值是双倍的,那么变量 i 将是双倍的。或者,如果表达式的值为 bool,则变量 i 将为 bool。
所以,让我们先学习类型推断,它基本上是指在编程语言中自动推断表达式的数据类型。
在 C++ 11 之前,c++ 中的所有变量都必须显式声明,但在 c++ 11 发布之后,编译器本身会在运行时推断变量的类型。
我们可以将它用于变量,甚至用于函数返回类型。但是,建议避免在函数返回类型中使用 auto。