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

5anewei6  于 2023-10-21  发布在  其他
关注(0)|答案(6)|浏览(166)

据我所知,decltypeauto都将试图找出某个东西的类型。
如果我们定义:

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;

请问decltypeauto的区别是什么?

of1yzvn4

of1yzvn41#

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"
 }

另请参阅大卫罗德里格斯的回答,关于只有autodecltype之一是可能的地方。

o7jaxewo

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

w9apscun

w9apscun3#

这就是我对auto和decltype的看法:
两者在实践中最明显的区别是:

  • 在expr的类型推导中,decltype推导出正确的类型(除了lvalue expr -> lvalue ref),auto默认为value。

我们需要先学习**“数据流”模型,然后才能理解两者的区别。
在我们的代码中,函数调用可以解析为数据流模型(类似于函数式程序的概念),所以被调用的函数是
数据接收者**,调用者是数据提供者。显然,数据类型必须由数据接收方决定,否则数据流中的数据无法按顺序组织。
看这个

template<typename T>
void foo(T t){
    // do something.
}

T将被推导为一个值类型,不管你是否传递。如果你想要引用类型,你应该使用auto&auto&&,这就是我所说的,数据类型由数据接收者决定。
让我们回到auto
auto用于对右值expr进行类型推导,为数据接收者提供正确的接口来接收数据。

auto a = some expr; // a is data receiver, and the expr is the provider.

那么为什么auto要忽略ref修饰符呢?因为它应该由接收器决定。

为什么需要decltype?

答案是:auto不能用作真正的类型演绎,它不会给予正确的expr类型。它只是给予数据接收器一个正确的类型来接收数据。
因此,我们需要decltype来获得正确的类型。

qpgpyjmq

qpgpyjmq4#

一般来说,如果你需要一个类型的变量,你要初始化,使用 auto*。decltype 当你需要一个非变量的类型时,比如一个返回类型,更好地使用。

eulz3vhy

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;

}
ubof19bj

ubof19bj6#

我认为auto是一个纯粹的简化功能,而decltype的主要目的是在基础库中实现复杂的元编程。然而,从语言技术的使用Angular 来看,它们是非常密切相关的。
来自HOPL20 4.2.1,Bjarne Stroustrup。

相关问题