C++中的decltype、std::declval 和 std::decay_t傻傻分不清楚

前言

在C++中提到推导第一个映入脑海的可能是“模板”,当然有人也可能想到 auto,这些都是和推导相关的语言语法,再比如“完美转发”等等,总是就是他们的类型不用明明白白的写出来,可以利用一种简单的方式来定义,比如 candidates 是一个字符串数组, 如果遍历它我们可以写成 for (auto& skillId : candidates),而不用将 skillId 变量定义成 const std::string&,这在一定程度上带来了便利,今天的几个东东也是用于推导的,我们一起来看看。

它们是什么

decltypestd::declvalstd::decay_t 都是 C++ 标准库中的类型相关工具,这些工具在 C++ 编程中提供了强大的类型推导和处理能力,使得代码更加灵活。

  • decltype 是一个关键字,用于从一个表达式中推导出其类型。它通常与表达式一起使用,以便在编译时确定表达式的类型。例如:

    1
    2
    int x = 5;
    decltype(x) y = 10; // y 的类型将被推导为 int

    decltype 还可以用于推导函数返回类型,以及在泛型编程中处理模板的类型。

  • std::declval 是一个函数模板,用于在不实际调用构造函数的情况下生成一个对象引用,以便在类型推导中使用。通常在需要引用某个类型的对象但实际无法创建该对象的上下文中使用,例如在函数返回类型推导中:

    1
    2
    3
    4
    template <typename T>
    auto createAndProcess() -> decltype(std::declval<T>().process()) {
    // 此处只是用于类型推导,并不会实际创建 T 的对象
    }

    在这个例子中,std::declval<T>().process() 用于推导函数的返回类型,但并不会实际调用 process 函数。

  • std::decay_t 是一个类型转换工具模板,用于将给定类型的”衰变”后的类型返回。衰变指的是将类型转换为其”自然”形式,即去掉引用、添加 cv 限定符(const 和 volatile)。例如:

    1
    2
    3
    using T1 = std::decay_t<int&>;      // T1 为 int
    using T2 = std::decay_t<const int>; // T2 为 int
    using T3 = std::decay_t<int[]>; // T3 为 int*

    std::decay_t 在模板编程中很有用,因为它可以帮助去除类型的多余限定符,使得函数模板的匹配更加精确。

通俗解释

如果看了上面的例子还是有点迷糊,那我再解释的通俗一点:

  • decltype 读音为 “dee-kluh-type”,就是返回一个变量的类型,比如你有一个对象 obj 想要再定义一个和它相同各类型的变量就可以写成 decltype(obj) newObj;

  • std::declval 读音为 “standard dee-cl-val”,它能返回类型 T 的右值引用,其实是一个伪实例,不会产生任何临时对象,也不会因为表达式很复杂而发生真实的计算。因为不会真正的进行构造,所以可以实现在元编程时伪构造一个没有定义默认构造函数类,还可以避开纯虚基类不能实例化的问题,说白了它就是假装创建个对象用于推导类型。

  • std::decay_t 读音为 “standard dee-kay tee”,有点褪去外表直击内心的意味,就是大家一起褪去花里胡哨的修饰符,获得原始的类型,用于函数模板的匹配更加精确,比如判断类型 T是不是int,if constexpr (std::is_same_v<std::decay_t<T>, int>)

总结

  • decltype 是关键字,用于有了值或对象求类型的
  • std::declval 是函数模板,用于伪造一个对象但不实际构造的
  • std::decay_t 是类模板,用于去除修饰符获取原始类型的
  • 没想到decltype 居然是关键字,结果一查发现C++的关键字已经膨胀了,下次总结一下
==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

当身边出现不和谐声音的时候问问自己,是不是你把他们招来的,用实力让他们闭嘴,而不要视图通过语言让他们明白

2023-9-5 21:42:25

Albert Shi wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客