据我了解,
decltype
和auto
都会尝试找出某物的类型。
如果我们定义:
int foo () {
return 34;
}
那么两个声明都是合法的:
auto x = foo();
cout << x << endl;
decltype(foo()) y = 13;
decltype(auto) y = 13; // alternatively, since C++14
cout << y << endl;
您能告诉我
decltype
和 auto
之间的主要区别是什么吗?
decltype
给出传递给它的表达式的 declared 类型。 auto
与模板类型推导的作用相同。因此,例如,如果您有一个返回引用的函数,则 auto
仍然是一个值(您需要 auto&
才能获取引用),但 decltype
将正是返回值的类型。
#include <iostream>
int global{};
int& foo()
{
return global;
}
int main()
{
decltype(foo()) a = foo(); //a is an `int&`
// decltype(auto) a = foo(); alternatively, since C++14
auto b = foo(); //b is an `int`
b = 2;
std::cout << "a: " << a << '\n'; //prints "a: 0"
std::cout << "b: " << b << '\n'; //prints "b: 2"
std::cout << "---\n";
decltype(foo()) c = foo(); //c is an `int&`
// decltype(auto) c = foo(); alternatively, since C++14
c = 10;
std::cout << "a: " << a << '\n'; //prints "a: 10"
std::cout << "b: " << b << '\n'; //prints "b: 2"
std::cout << "c: " << c << '\n'; //prints "c: 10"
}
另请参阅 David Rodríguez 关于仅可能出现
auto
或 decltype
之一的地方的回答。
这是 C++11 问题的 C++11 答案
auto
(在推断类型的上下文中)仅限于定义具有初始值设定项的变量的类型。 decltype
是一个更广泛的构造,以额外信息为代价,将推断表达式的类型。
在可以使用
auto
的情况下,它比 decltype
更简洁,因为您不需要提供从中推断类型的表达式。
auto x = foo(); // more concise than `decltype(foo()) x`
std::vector<decltype(foo())> v{ foo() }; // cannot use `auto`
当使用函数的尾随返回类型时,关键字
auto
也用在完全不相关的上下文中:
auto foo() -> int;
那里
auto
只是一个引导符,以便编译器知道这是一个带有尾随返回类型的声明。虽然上面的示例可以轻松转换为旧样式,但在泛型编程中它很有用:
template <typename T, typename U>
auto sum( T t, U u ) -> decltype(t+u)
请注意,在这种情况下,
auto
不能用于定义返回类型。
这是我对 auto 和 decltype 的思考:
两者在实践中最明显的区别是:
decltype
推导正确的类型(左值 expr -> 左值 ref 除外)并且 auto
默认为 value。在了解差异之前,我们需要学习“数据流”模型。
在我们的代码中,函数调用可以解析为数据流模型(类似于函数式程序的概念),因此被调用的函数是数据接收者,调用者是数据提供者。显然,数据类型必须由数据接收者决定,否则数据无法在数据流中按顺序组织。
看这个:
template<typename T>
void foo(T t){
// do something.
}
无论你是否通过,T都会被推导为值类型。 如果你想要ref类型,你应该使用
auto&
或auto&&
,这就是我的意思,数据类型由数据接收者决定。
让我们回到
auto
:
auto
用于对右值expr进行类型推导,为数据接收者提供正确的接口来接收数据。
auto a = some expr; // a is data receiver, and the expr is the provider.
那么为什么dose
auto
忽略ref修饰符呢?
因为这应该由接收者决定。
答案是:
auto
不能用作真实类型推导,它不会为您提供 expr 的正确类型。它只是为数据接收器提供正确的类型来接收数据。
因此,我们需要 decltype 来获取正确的类型。
通常,如果您需要要初始化的变量的类型,请使用 auto。当您需要非变量的类型(例如返回类型)时,最好使用 decltype。
修改@Mankarse的示例代码,我认为更好的一个爆炸了:
#include <iostream>
int global = 0;
int& foo()
{
return global;
}
int main()
{
decltype(foo()) a = foo(); //a is an `int&`
auto b = foo(); //b is an `int`
b = 2;
std::cout << "a: " << a << '\n'; //prints "a: 0"
std::cout << "b: " << b << '\n'; //prints "b: 2"
std::cout << "global: " << global << '\n'; //prints "global: 0"
std::cout << "---\n";
//a is an `int&`
a = 10;
std::cout << "a: " << a << '\n'; //prints "a: 10"
std::cout << "b: " << b << '\n'; //prints "b: 2"
std::cout << "global: " << global << '\n'; //prints "global: 10"
return 0;
}
我认为 auto 是一个纯粹的简化功能,而 decltype 的主要目的是 在基础库中启用复杂的元编程。然而他们非常接近 从语言技术使用的角度来看是相关的。
来自 HOPL20 4.2.1,Bjarne Stroustrup。