zoukankan      html  css  js  c++  java
  • c++11——auto,decltype类型推导

        c++11中引入了auto和decltype关键字实现类型推导,通过这两个关键字不仅能够方便的获取复杂的类型,而且还能简化书写,提高编码效率。 
        auto和decltype的类型推导都是编译器在编译的时候完成的,auto是通过定义auto变量时候给出的表达式的值推导出实际类型,并且在声明auto变量时必须马上初始化;decltype通过表达式的值推导出实际的类型,但是可以只声明变量,而不赋值。

    auto类型推导

    1. auto推导
        auto x = 5; //被编译器推导为int类型
        auto pi = new auto(1); //编译器推导为int
        const auto* v = &x, u = 5; //v为 const int*, u为 const int
        static auto y = 0.1; //y为static const double
        auto s; //出错! auto变量不能只声明不初始化
    
    2. auto推导规则

    (1)当不声明为指针或引用时,auto的推导结果和初始化表达式抛弃引用和cv限定符后的类型一致;(cv限定符: const volatile限定符) 
    (2)当声明为指针或引用时,auto的推导结果将保留初始化表达式的cv限定符。

        int x = 0;
        auto *a = &x; //a为 int*
        auto b = &x; //b为 int*,auto可以自动识别指针类型
        auto &c = x; //c为 int&
        const auto e = x; //e为const int
        auto f = e; //f为int (非指针或引用,则不保留cv限定符)
        const auto& g = x; //g 为 const int&
        auto& h = g; //h 为 const int&(指针或引用,保留cv限定符)
        auto k = g;
    
    3. auto的限制

    (1)auto不能用于函数参数 
    (2)auto不能用于非静态成员变量 
    (3)auto无法定义数组 
    (4)auto无法推导出模板参数

    void func(auto a = 1){};   //错误。auto不能用于函数参数
    struct Foo{
        auto var1 = 0;      //错误,auto不能用于非晶态成员变量
        static const auto var2 = 0;
    }

    template<typename T>
    struct Bar{};

    int main(){
        int arr[10] = {0};
        auto aa = arr;  //aa被推导为int*
        auto rr[10] = arr;  //错误,auto无法定义数组
        Bar<int> bar;
        Bar<auto> bb = bar; //错误,auto无法推导出模板参数
    }
    4. auto的使用场景

    (1)变量类型名比较长比较复杂

        //比如stl容器
        std::map< double, double> result_map;
        std::map< double, double>::iterator it = result_map.begin();
        for(; it != result_map.end(); ++ it){};
        //通过auto可以简化为
        for (auto it = result_map.begin(); it != result_map.end(); ++it);
        std::unordered_multimap< int, int> result_map;
        std::pair< std::unordered_multimap< int, int>::iterator, std::unordered_multimap< int, int>::iterator> range = result_map.equal_range(key);
        //通过auto简化为
        auto range = result_map.equal_range(key);
    

    (2)无法确定变量应该定义为什么类型

    class Foo{
    public:
        static int get(void){
            return 0;
        }
    };
    class Bar{
    public:
        static const char* get(){
            return "hello world";
        }
    };
    
    template<typename A>
    void func(void){
        auto val = A::get();
        cout << val << endl;
    }
    int main(){
        func<Foo>();
        func<Bar>();
    }
    

    decltype类型推导

    1. decltype推导

        decltype可以在编译时推导一个表达式的类型,语法格式如下: 
    decltype(exp). decltype只是推导表达式的类型,并不会对表达式求值。

        int x = 0;
        decltype(x) y = 3; //y被推导为int类型
        decltype(x + y) z = 0; //z被推导为int
        const int a = 1;
        decltype(a) b = 2; //被推导为const int,尽管非指针或引用,仍然保持cv限定符
        const int& i = 9;
        decltype(i) h = x; //const int&
        decltype(z)* p = &x; //p 为int*
    

        decltype通过表达式得到的类型,可以保留住表达式的引用以及const限定符。对于一般的标记符表达式,decltype精确的推导出表达式定义本身的类型,不会像auto那样舍弃引用和cv限定符

    2. decltype推导规则

    (1) exp是标识符,类访问表达式,decltype(exp)和exp的类型一致 
    (2) exp是函数调用,decltype(exp)和返回值的类型一致 
    (3) 其他情况,若exp是一个左值,则decltype(exp)是exp类型的左值引用,否则为和exp类型一致。

    (1) exp是标识符,类访问表达式,decltype(exp)和exp的类型一致
    (2) exp是函数调用,decltype(exp)和返回值的类型一致
    (3) 其他情况,若exp是一个左值,则decltype(exp)是exp类型的左值引用,否则为和exp类型一致。
    
    ```
    (1)标识符、类访问表达式,则 decltype(exp)和exp的类型一致
    class Foo{
    public:
        static const int Number = 0;
        int x;
    };
    int n = 0;
    volatile const int& x = n;
    decltype(n) a = n;          //int
    decltype(x) b = n;          //volatile const int&
    decltype(Foo::Number) c = 0;    //const int(没有static)
    
    Foo foo;
    decltype(foo.x) d = 0;  //int类型
    
    (2) 函数调用,decltype(f(xx)) 和 函数返回值类型一致
    const Foo f(){
    ...
    }
    decltype(f()) c;    //const Foo
    
    (3) 带括号的表达式和加法运算表达式
    struct Foo{
        int x;
    };
    const Foo foo = Foo();
    decltype(foo.x) a = 0;      //a 被推导为int, 根据推导规则1
    decltype((foo.x))b = a;     //b 被推导为const int&,
    //因为根据foo.x 为一个左值,可知括号表达式也是一个左值。则按照推导规则3,返回左值的引用,foo为const Foo,则foo.x为一个const int类型的左值,则decltype的推导结果 为 const int&
    
    int n = 1, m = 2;
    decltype(n + m) c = 0;      //c被推导为int, n + m 为右值,则推导规则3,  
    decltype(n += m) d = c;     //d被推导为int &, n += m 为左值,则推导规则3,为exp的引用
    //注意此时 n 仍然为1,而不是3,因为 decltype只是推导exp的类型,而不对exp进行求值
    
    3. decltype的实际应用

    (1)泛型编程中自动推导类型

    1. decltype(ContainerT().begin()) it_; //获得某种类型容器的迭代器

    (2)通过变量表达式抽取变量类型

        vector<int> v;
        ....
        decltype(v)::value_type i = 0; //知道v是一个vector,但是不知道里面的数据类型,则可以使用 decltype(v)::value_type
    

    返回类型后置语法,auto和decltype结合使用

        

    int& foo(int& i);
    float foo(float& f);
    //有如上两个函数,同名,但是返回值和参数类型不同。若想要用模板来实现两个同名函数的调用。
    template<typename T>
    decltype(foo(val)) func(T&val){
        return val;
    }   //这样写编译不过,因为c++的返回值是前置语法,在返回值定义的时候参数变量还不存在,因此无法使用前置的decltype(foo(val)) 【需要获得decltype(foo(val))的时候,val还不存在】
    
    但可以通过auto和decltype的自动类型推导完成。
    template<typename T>
    auto func(T& val) -> decltype(foo(val)) //返回值类型后置
    {
        return foo(val);
    }
    
  • 相关阅读:
    第五周作业
    2019春第四周作业编程总结
    2019春第四周作业
    2019春第二周作业编程总结
    2019春第一周作业编程总结
    自我认识
    对我影响最大的三位老师
    C语言I博客作业04
    C语言I博客作业03
    C语言I博客作业02
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/4802578.html
Copyright © 2011-2022 走看看