decltype 和 auto 作为变量的占位符类型有什么区别?

问题描述 投票:0回答:6

据我了解,

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
之间的主要区别是什么吗?

c++ type-inference auto decltype
6个回答
74
投票

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
之一的地方的回答。


50
投票

这是 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
不能用于定义返回类型。


3
投票

这是我对 auto 和 decltype 的思考:

两者在实践中最明显的区别是:

  • 在 expr 的类型推导中,
    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修饰符呢? 因为这应该由接收者决定。

为什么我们需要 decltype?

答案是:

auto
不能用作真实类型推导,它不会为您提供 expr 的正确类型。它只是为数据接收器提供正确的类型来接收数据。

因此,我们需要 decltype 来获取正确的类型。


0
投票

通常,如果您需要要初始化的变量的类型,请使用 auto。当您需要非变量的类型(例如返回类型)时,最好使用 decltype


0
投票

修改@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;

}

0
投票

我认为 auto 是一个纯粹的简化功能,而 decltype 的主要目的是 在基础库中启用复杂的元编程。然而他们非常接近 从语言技术使用的角度来看是相关的。

来自 HOPL20 4.2.1,Bjarne Stroustrup。

© www.soinside.com 2019 - 2024. All rights reserved.