• C++ decltype 类型推导


    decltype 说明符(C++11)

    C++11 引入了 decltype 说明符,decltype 可以获取一个对象或者表达式的类型。

    使用起来也很简单:

    #include 
    
    int main() {
        int x1 = 0;
        decltype(x1) x2 = 0;        // x2 被推导为 int 类型(变量 x1 的类型)
        std::cout << typeid(x2).name() << std::endl; 
    
        double x3 = 0;
        decltype(x1 + x3) x4 = x1 + x3;     // x4 被推导为 double 类型(表达式 x1 + x3 的类型)
        std::cout << typeid(x4).name() << std::endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    运行结果:

    linrongjian@hhb-ssd:/data/modern_cpp$ g++ -std=c++11 decltype_example.cpp -o decltype_example
    linrongjian@hhb-ssd:/data/modern_cpp$ ./decltype_example 
    i
    d
    
    • 1
    • 2
    • 3
    • 4

    相比 autodecltype 除了可以推导表达式的类型,还可以用来推导类中的非静态成员变量的类型(auto 是不可以的),

    使用 decltype 保留auto 的引用属性(C++14)

    之前讲 auto 关键字的时候说过 auto 的推导规则其中之一是:使用 auto 声明变量初始化时,目标对象如果是引用,则引用属性会被忽略。

    比如下面的代码:

    #include 
    #include 
    #include 
    
    template 
    auto return_ref(T& t) {
        return t;
    }
    
    int main() {
        int x1 = 0;
        static_assert(std::is_reference_v);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    我们引用传递参数 t,希望 return_ref 可以返回一个引用,然而事实上这里 auto 被推导为值类型:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8WsFDzCL-1662564333542)(C:\Users\Lin\AppData\Roaming\Typora\typora-user-images\image-20220907225422784.png)]

    一个解决办法是给 auto 加上 &,另一个解决办法就是使用 decltype 作为尾置返回类型:

    #include 
    #include 
    #include 
    
    template 
    auto return_ref(T& t) -> decltype(t) {
        return t;
    }
    
    int main() {
        int x1 = 0;
        static_assert(std::is_reference_v);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    decltype 的推导规则

    对于一个类型为 T 的变量或者表达式 edecltype(e) 的推导规则有 5 条:

    1. 如果 e 是一个未加括号的表达式(结构化绑定除外)或者未加括号的类成员访问,则 decltype(e) 推断出 e 的类型是 T

      如果不存在这样的类型(比如表达式里的变量不在当前作用域内)或者 e 是重载函数(运行时多态,decltype 要求是编译期确定返回类型),则无法进行推导。

    2. 如果 e 是一个函数调用或者仿函数调用,那么 decltype(e) 推断出的类型是其返回值的类型。

    3. 如果 e 是一个类型为 T 的左值,则 decltype(e)T&

      这就是上面的那个例子返回的是一个引用的原因。

    4. 如果 e 是一个类型为 T 的将亡值,则 decltype(e)T&&

    5. 其他情况,decltype(e)T

    cv 限定符(const / volatile)的推导

    decltype(e) 推导的类型会同步 ecv 限定符。

    比如:

    const int i = 0;
    decltype(i);	// declytpe(i) 推导类型为 const(注意这里和 auto 的不同)
    
    • 1
    • 2

    如果 e 是类的成员变量时,要同步 cv 限定符需要加上括号。

    struct A {
        double x;
    };
    const A* a = new A();
    decltype(a->x);		// decltype(a->x) 推导类型为 double,const 属性被忽略
    
    • 1
    • 2
    • 3
    • 4
    • 5

    上面的代码没有给 a->x 加上括号,推导的类型没有 const 属性,带上括号之后推导类型为 const double

    struct A {
        double x;
    };
    const A* a = new A();
    decltype((a->x));	// decltype((a->x)) 推导类型为 const double
    
    • 1
    • 2
    • 3
    • 4
    • 5

    总结:当 e 是加上了括号的数据成员时,父对象表达式的 cv 限定符会同步到推导结果。

    decltype(auto) (C++14)

    C++14 运行时用 decltype(auto) 告诉编译器使用 decltype 的规则来推导 auto.

    decltype(auto) 必须单独使用,也就是不能再给它加上指针、引用还有 cv 属性。

    再看之前的 return_ref 的例子,如果我们还是想用 auto 来给 return_ref 函数返回一个引用,而我们却不想使用 auto&(在泛型编程的情况下只能表现引用语义的表达能力是不够的),就可以使用 decltype(auto)

    #include 
    #include 
    #include 
    
    template 
    decltype(auto) return_ref(T& t) {
        return t;
    }
    
    int main() {
        int x1 = 0;
        static_assert(std::is_reference_v);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这里由于使用了 decltype(auto),因此 auto 按照 decltype 的规则来推导类型,这里 e 是个左值引用,按照推导规则 3,返回一个引用,所以我们的断言可以通过。

    参考资料

    1. 现代C++语言核心特性解析
    2. cppreference: decltype specifier
  • 相关阅读:
    浅谈电弧光保护装置在6KV厂用电系统中的应用与选型
    机器学习如何做到疫情可视化——疫情数据分析与预测实战
    防御安全第五次作业
    ARM底层汇编基础指令
    Unity的OnOpenAsset:深入解析与实用案例
    【C++编程能力提升】
    渗透必备:Proxifier玩转代理
    MATLAB使用速成 第七章(多项式运算与代数方程求解)
    自动化运维工具Ansible之playbooks剧本
    记一次生产中使用CompletableFuture遇到的坑
  • 原文地址:https://blog.csdn.net/RJ_theMag/article/details/126756006