据我所知,decltype和auto都将试图找出某个东西的类型。如果我们定义:
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的区别是什么?
of1yzvn41#
decltype给出传递给它的表达式的 declared 类型。auto的作用与模板类型演绎相同。因此,例如,如果你有一个返回引用的函数,auto仍然是一个值(你需要auto&来获取引用),但decltype将完全是返回值的类型。
auto&
#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" }
另请参阅大卫罗德里格斯的回答,关于只有auto或decltype之一是可能的地方。
o7jaxewo2#
这是C11对C11问题的回答
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不能用于定义返回类型。
w9apscun3#
这就是我对auto和decltype的看法:两者在实践中最明显的区别是:
我们需要先学习**“数据流”模型,然后才能理解两者的区别。在我们的代码中,函数调用可以解析为数据流模型(类似于函数式程序的概念),所以被调用的函数是数据接收者**,调用者是数据提供者。显然,数据类型必须由数据接收方决定,否则数据流中的数据无法按顺序组织。看这个
template<typename T> void foo(T t){ // do something. }
T将被推导为一个值类型,不管你是否传递。如果你想要引用类型,你应该使用auto&或auto&&,这就是我所说的,数据类型由数据接收者决定。让我们回到auto:auto用于对右值expr进行类型推导,为数据接收者提供正确的接口来接收数据。
auto&&
auto a = some expr; // a is data receiver, and the expr is the provider.
那么为什么auto要忽略ref修饰符呢?因为它应该由接收器决定。
答案是:auto不能用作真正的类型演绎,它不会给予正确的expr类型。它只是给予数据接收器一个正确的类型来接收数据。因此,我们需要decltype来获得正确的类型。
qpgpyjmq4#
一般来说,如果你需要一个类型的变量,你要初始化,使用 auto*。decltype 当你需要一个非变量的类型时,比如一个返回类型,更好地使用。
eulz3vhy5#
修改@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; }
ubof19bj6#
我认为auto是一个纯粹的简化功能,而decltype的主要目的是在基础库中实现复杂的元编程。然而,从语言技术的使用Angular 来看,它们是非常密切相关的。来自HOPL20 4.2.1,Bjarne Stroustrup。
6条答案
按热度按时间of1yzvn41#
decltype
给出传递给它的表达式的 declared 类型。auto
的作用与模板类型演绎相同。因此,例如,如果你有一个返回引用的函数,auto
仍然是一个值(你需要auto&
来获取引用),但decltype
将完全是返回值的类型。另请参阅大卫罗德里格斯的回答,关于只有
auto
或decltype
之一是可能的地方。o7jaxewo2#
这是C11对C11问题的回答
auto
(在它推断类型的上下文中)仅限于定义有初始化器的变量的类型。decltype
是一个更广泛的结构,它以额外的信息为代价,将推断表达式的类型。在可以使用
auto
的情况下,它比decltype
更简洁,因为您不需要提供从中推断类型的表达式。关键字
auto
也用于一个完全不相关的上下文中,当函数使用尾随返回类型时:auto
只是一个前导,这样编译器就知道这是一个带有尾随返回类型的声明。虽然上面的例子可以简单地转换为旧的风格,但在泛型编程中它是有用的:注意,在这种情况下,
auto
不能用于定义返回类型。w9apscun3#
这就是我对auto和decltype的看法:
两者在实践中最明显的区别是:
decltype
推导出正确的类型(除了lvalue expr -> lvalue ref),auto
默认为value。我们需要先学习**“数据流”模型,然后才能理解两者的区别。
在我们的代码中,函数调用可以解析为数据流模型(类似于函数式程序的概念),所以被调用的函数是数据接收者**,调用者是数据提供者。显然,数据类型必须由数据接收方决定,否则数据流中的数据无法按顺序组织。
看这个
T将被推导为一个值类型,不管你是否传递。如果你想要引用类型,你应该使用
auto&
或auto&&
,这就是我所说的,数据类型由数据接收者决定。让我们回到
auto
:auto
用于对右值expr进行类型推导,为数据接收者提供正确的接口来接收数据。那么为什么
auto
要忽略ref修饰符呢?因为它应该由接收器决定。为什么需要decltype?
答案是:
auto
不能用作真正的类型演绎,它不会给予正确的expr类型。它只是给予数据接收器一个正确的类型来接收数据。因此,我们需要decltype来获得正确的类型。
qpgpyjmq4#
一般来说,如果你需要一个类型的变量,你要初始化,使用 auto*。decltype 当你需要一个非变量的类型时,比如一个返回类型,更好地使用。
eulz3vhy5#
修改@Mankarse的示例代码,我认为更好的一个吹:
ubof19bj6#
我认为auto是一个纯粹的简化功能,而decltype的主要目的是在基础库中实现复杂的元编程。然而,从语言技术的使用Angular 来看,它们是非常密切相关的。
来自HOPL20 4.2.1,Bjarne Stroustrup。