C++ auto和decltype的区别

 

 

#include <iostream>
using namespace std;
int main() {
    int n = 10;
    int &r1 = n;
    //auto推导
    auto r2 = r1;
    r2 = 20;
    cout << n << ", " << r1 << ", " << r2 << endl;
    //decltype推导
    decltype(r1) r3 = n;
    r3 = 99;
    cout << n << ", " << r1 << ", " << r3 << endl;
    return 0;
}

 

 

 

root@ubuntu:~/c++# g++ -std=c++11  auto.cpp -o auto
root@ubuntu:~/c++# ./auto
10, 10, 20
99, 99, 99

decltype
decltype是C++11新增的关键字,主要用于提取变量和表达式的类型。
decltype的语法形式为:decltype(e),这里e是一个表达式,而decltype(e)是一个类型指示符。decltype的结果不是值,而是一个类型。
decltype的语法规则主要有以下四条:
如果e是一个没有用小括号括起来的标识符表达式或类成员存取表达式,那么decltype(e)的结果类型为该表达式中标识符的声明类型。
注:这里的小括号是指表达式e自身带的小括号,而不是decltype(e)中的小括号。
如果e是T类型的x值,那么decltype(e)的结果类型为T&&。
注:x值(xvalue)是C++11新引入的值的种类,介于传统的左值和右值之间。最常见的x值为无名右值引用。
如果e是T类型的左值,那么decltype(e)的结果类型为T&。
注:同时满足规则1和规则3的情况下,规则1优先。
如果e是T类型的纯右值,那么decltype(e)的结果类型为T。
注:纯右值(prvalue)即传统右值。字面量以及临时对象都是纯右值。
测试代码及出错信息 

#include <iostream>
 
template<typename T>
T f();
 
struct S {int a;};
 
int main()
{
    int a = 0;
    S s;
    f<decltype(a)>();
    f<decltype(s.a)>();
    f<decltype(std::move(a))>();
    f<decltype((a))>();
    f<decltype((s.a))>();
    f<decltype(0)>();
 
    decltype(a) b = a; // int b = a;
    decltype((a)) c = a; // int& c = a;
}

 

 

 

root@ubuntu:~/c++# g++ -std=c++14  auto.cpp -o auto
/tmp/ccRONFza.o: In function `main':
auto.cpp:(.text+0x20): undefined reference to `int f<int>()'
auto.cpp:(.text+0x24): undefined reference to `int f<int>()'
auto.cpp:(.text+0x28): undefined reference to `int&& f<int&&>()'
auto.cpp:(.text+0x2c): undefined reference to `int& f<int&>()'
auto.cpp:(.text+0x30): undefined reference to `int& f<int&>()'
auto.cpp:(.text+0x34): undefined reference to `int f<int>()'
collect2: error: ld returned 1 exit status
root@ubuntu:~/c++# 

这段代码使用了一种特殊技巧来查看decltype的结果类型。代码中定义了一个未被实现的函数模板f,该函数模板有一个类型参数T。如果用某个类型T来调用该函数模板,编译器就会因找不到函数模板的定义而输出”T f<T>()未被定义“的出错信息。也就是说,利用该函数模板,我们便可以在编译器所输出的出错信息中检查模板参数T的实际类型。在main函数内,我们充分利用了这一个技巧,通过利用decltype的结果类型调用该函数模板来让编译器输出相应的类型。
从出错信息中可以得知:

decltype(a)和decltype(s.a)的结果类型为int。(适用规则1)
理由:a是未带外围小括号的标识符,s.a是未带外围小括号的类成员存取表达式。变量a的声明类型是int,S结构的成员变量a的声明类型也是int。
decltype(std::move(a))的结果类型为int&&。(适用规则2)
理由:std::move(a)是无名右值引用,是x值的一种。
decltype((a))和decltype((s.a))的结果类型为int&。(适用规则3)
理由:(a)和(s.a)都是带外围小括号的左值引用,是左值。
decltype(0)的结果类型为int。(适用规则4)
理由:0是纯右值(即传统右值)。
 

 

decltype(auto)

decltype(auto)是C++14新增的类型指示符,可以用来声明变量以及指示函数返回类型。
当decltype(auto)被用于声明变量时,该变量必须立即初始化。假设该变量的初始化表达式为e,那么该变量的类型将被推导为decltype(e)。也就是说在推导变量类型时,先用初始化表达式替换decltype(auto)当中的auto,然后再根据decltype的语法规则来确定变量的类型。
decltype(auto)也可以被用于指示函数的返回值类型。假设函数返回表达式e,那么该函数的返回值类型将被推导为decltype(e)。也就是说在推导函数返回值类型时,先用返回值表达式替换decltype(auto)当中的auto,然后再根据decltype的语法规则来确定函数返回值的类型。
 

#include <iostream>
 
template<typename T>  
T f();
 
struct S {int a;};
 
int a = 0;
S s;
decltype(auto) g1() {return s.a;}
decltype(auto) g2() {return std::move(a);}
decltype(auto) g3() {return (a);}
decltype(auto) g4() {return (0);}
 
int main()
{
    decltype(auto) i1 = a;
    decltype(auto) i2 = std::move(a);
    decltype(auto) i3 = (s.a);
    decltype(auto) i4 = (0);
    f<decltype(i1)>();
    f<decltype(i2)>();
    f<decltype(i3)>();
    f<decltype(i4)>();
f
<decltype(g1())>(); f<decltype(g2())>(); f<decltype(g3())>(); f<decltype(g4())>(); }

 

 

 

"auto.cpp" 30L, 572C written                                                                                                                                                                                                    
root@ubuntu:~/c++# g++ -std=c++14  auto.cpp -o auto
/tmp/ccSvkNQi.o: In function `main':
auto.cpp:(.text+0x78): undefined reference to `int f<int>()'
auto.cpp:(.text+0x7c): undefined reference to `int&& f<int&&>()'
auto.cpp:(.text+0x80): undefined reference to `int& f<int&>()'
auto.cpp:(.text+0x84): undefined reference to `int f<int>()'

auto.cpp:(.text+0x88): undefined reference to `int f<int>()' auto.cpp:(.text+0x8c): undefined reference to `int&& f<int&&>()' auto.cpp:(.text+0x90): undefined reference to `int& f<int&>()' auto.cpp:(.text+0x94): undefined reference to `int f<int>()' collect2: error: ld returned 1 exit status root@ubuntu:~/c++#

 

posted on 2021-08-03 10:38  tycoon3  阅读(191)  评论(0编辑  收藏  举报

导航