(转载)decltype和declval的用法

本文详细介绍了C++11中的两种新特性:decltype用于获取表达式的类型,declval用于创建临时右值引用。通过多个示例展示了如何使用这两种特性来简化类型推导过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
增加对两者的描述,图片来自c++标准库第2版

下面这部分转载:

1. decltype是c++11以后出现的一个新的关键字,是用来萃取表达式或者变量或者函数返回值的类型的。

具体用法可以参考官网:https://en.cppreference.com/w/cpp/language/decltype

2. declval是c++11中的一个模板函数,原型如下:

具体用法可以参考官网:https://zh.cppreference.com/w/cpp/utility/declval

template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;

将任意类型 T 转换成引用类型,令在 decltype 表达式中不必经过构造函数就能使用成员函数。

3.使用案例

#include <type_traits>
#include <utility>
 
int func(int){return 0;} //普通函数
typedef int(*pFunc)(); //函数指针
typedef int(&refFunc)(); //函数引用
struct ClassFunc
{
    char operator()(int) { return '0'; }
    int operator()(bool) { return 0; }
    int test() { return 0; }
    float test(int) { return 0; }
    static double test(float) { return 0; }
 
    float MyFunc(int) { return 0; }
    static int MyTest(int) { return 0; }
};
 
void main()
{
    int a;
    int b;
    decltype(a) c; //int
    //双层括号的,则解析为int&
    decltype((a)) cc = c; //int&
    decltype(a + b) d; //int
 
    //萃取一个有参函数的返回值时,需给参数传值,不能写成func(int)
    decltype(func(0)) e; //int
 
    //这里萃取到的是一个函数指针,没有理解
    decltype(pFunc()) f;//int(*)();
 
    auto lambdaFunc = []()->int {return 0; };
    /*
    这个必须还要把lambdaFunc赋值给ff,否则就报错
    无法引用 "lambda []()->int"的默认构造函数--它是已删除的函数,无法构造lambda实例
    */
    decltype(lambdaFunc) ff= lambdaFunc;
 
    //类构造一个匿名对象,然后萃取该匿名对象的类型
    decltype(ClassFunc()) g; //ClassFunc
 
    /*萃取ClassFunc::operator()(int)的返回类型,通过调用成员函数的方式来触发萃取*/
    decltype(ClassFunc()(0)) h; //char
    decltype(ClassFunc()(false)) i; //int
    decltype(ClassFunc().test()) j; //int
    decltype(ClassFunc().test(0)) k; //float
    //因为是静态成员函数,所以可以直接通过类的方式来调用,从而萃取返回类型
    decltype(ClassFunc::test(1.2f)) m; //double
    decltype(ClassFunc().test(1.2f)) n; //double
 
    /*当ClassFunc的构造函数为私有的时候,那么是不能通过构造一个对象去调用函数,然后萃取返回类型的。
    此时需要 declval 来转换一个引用类型,然后调用类成员函数。
    */
    decltype(std::declval<ClassFunc>().test(0)) p; //float
}
<< `decltype` `std::invoke_result` 是 C++ 中用于类型推导的工具,但它们的作用使用场景有所不同。 ### 解决方法及详细解释: #### 1. **`decltype` 的作用** - `decltype` 是一种编译期关键字,用来根据表达式或变量推导出其类型。 - 它不仅可以推导普通变量的类型,还可以推导函数返回值、复杂表达式的类型等。 - 关键点在于它是基于声明语法而不是实际执行结果来确定类型的。 ```cpp #include <iostream> #include <typeinfo> int main() { int a = 42; decltype(a) b = a; // 推导出 b 的类型为 int std::cout << "Type of b: " << typeid(b).name() << "\n"; } ``` **特点:** - 不依赖于运行时行为(纯粹是静态分析)。 - 对未定义的行为同样适用——只要能够正确解析即可。 --- #### 2. **`std::invoke_result` 的作用** - 自 C++17 引入以来,`std::invoke_result<F, Args...>` 提供了一种更方便的方式去判断调用某种可调用实体(如函数指针、lambda 表达式、绑定器等)后的返回类型。 - 其本质是对各种可能被调用的情况进行了封装并标准化处理。 示例代码如下: ```cpp #include <functional> #include <type_traits> #include <string> #include <iostream> void greet(const std::string& name){ std::cout << "Hello, " << name << '\n'; } template<typename F, typename ...Args> using invoke_return_t = typename std::invoke_result<F, Args...>::type; int main(){ using ret_type_greet = invoke_return_t<decltype(greet), const std::string&>; if constexpr(std::is_same_v<ret_type_greet,void>){ std::cout<<"Function 'greet' returns void.\n"; } } ``` **注意**: 如果无法成功进行“调用”(例如参数不匹配),那么程序将不能通过编译检查;这是因为它实际上试图模拟整个过程从而得出结论。 --- ### 区别总结: | 特性 | decltype | std::invoke_result | |---------------------|-----------------------------------------------------------------------------------------------|---------------------------------------------------------------| | 主要用途 | 根据给定标识符/表达式直接获取对应的原始类型 | 分析某个 callable object 在特定输入下会产生的输出类型 | | 是否涉及函数调用 | 否。只关心单个元素本身的性质 | 是。需要考虑完整地构造一次假设中的 function call | | 编译失败情况下的表现形式 | 若目标非法,则产生编译错误 | 当尝试求解非可行方案时导致硬性的 compile-time failure | 因此可以说二者各有侧重,并且适用于完全不同层面的问题解决过程中! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值