• 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++#
  • 相关阅读:
    莫比乌斯反演学习笔记
    NOIp 2020 游记
    题解【LOJ3087】「GXOI / GZOI2019」旅行者
    题解【CF999E】Reachability from the Capital
    题解【LOJ2007】「SCOI2015」国旗计划
    题解【LOJ3145】「APIO2019」桥梁
    题解【LOJ2114】「HNOI2015」菜肴制作
    CSP-J/S 2020 爆炸记
    题解【洛谷P2569】[SCOI2010]股票交易
    补题目录
  • 原文地址:https://www.cnblogs.com/dream397/p/15093239.html
Copyright © 2020-2023  润新知