如何在C++11中用decltype实现make_logger函数并适配代码?
问题:C++11环境下用decltype实现make_logger函数
先把我们手头的现有代码梳理清楚,方便后续分析:
基础加法函数
#include <iostream> #include <functional> #include <string> using namespace std; // 为了C++11环境下代码简洁,避免重复写std::前缀 float add(float x, float y) { cout << "\n in the add function \n"; float res = x + y; cout << "\n exiting the add function \n"; return res; }
Logger类的前向声明与实现
// 前向声明 template <typename> struct Logger; // 针对函数类型的特化实现 template<typename R, typename... Args> struct Logger<R(Args...)> { function<R(Args...)> func; string name; // 构造函数 Logger(const function<R(Args...)>& func, const string& name) : func{func}, name{name} { } // 重载函数调用运算符 R operator()(Args... args) const { cout << "\n Entering Into ... .......\n" << name << endl; R result = func(args...); // 调用被包装的基础函数 cout << "\n Exiting from ... \n" << name << endl; return result; } };
原make_logger函数与使用示例
// 原make_logger实现 template <typename R, typename... Args> auto make_logger(R (*func)(Args...), const string& name) { return Logger<R(Args...)>{function<R(Args...)>(func), name}; } // 使用示例 int main() { auto logger_add = make_logger(add, "**Adding Numbers**"); auto result = logger_add(2.0f, 3.0f); // 注意C++11里浮点数字面量默认是double,用2.0f匹配float参数更严谨 return 0; }
核心问题解答
1. 原代码能在C++11环境运行吗?
可以,但需要注意两个关键细节:
- 必须手动包含必要的头文件:
<iostream>、<functional>、<string>,C++11不会自动引入这些标准库头文件 - 调用
logger_add时,建议传入float类型的字面量(比如2.0f),而非默认的double类型(2.0),虽然隐式转换也能运行,但显式匹配参数类型更符合C++11的类型严谨性要求
2. 如何用decltype实现make_logger?
原make_logger需要显式指定模板参数R和Args...,用decltype可以让编译器自动推导函数类型,实现更通用的包装逻辑。在C++11里,因为auto作为返回类型时需要尾置返回类型(trailing return type),具体写法如下:
// 基于decltype的make_logger实现(完全兼容C++11) template <typename Func> auto make_logger(Func func, const string& name) -> Logger<decltype(func)> { return Logger<decltype(func)>{function<decltype(func)>(func), name}; }
为什么这样可行?
- 模板参数
Func可以接受任意可调用对象:函数指针、lambda、std::function都能适配,比原版本的适用范围更广 decltype(func)会直接获取传入函数的原始类型,比如add的类型是float(float, float),正好匹配我们的Logger<R(Args...)>特化模板- 尾置返回类型
-> Logger<decltype(func)>是C++11里auto作为返回类型时的必要写法,用来明确告诉编译器返回值的具体类型 - 构造
Logger时,function<decltype(func)>(func)把传入的可调用对象转换成对应的std::function实例,完美匹配Logger构造函数的参数要求
用这个版本的make_logger,原有的使用示例完全不需要修改就能正常运行,而且还能无缝包装其他类型的函数(比如int(int, int)类型的加法函数),不需要修改make_logger的代码。
内容的提问来源于stack exchange,提问作者rrai
相关产品推荐
相关产品推荐

