C++如何在宏内调用类私有函数以获取调用位置行号等信息
原代码问题说明
- 宏定义写在类内部是错误做法,预处理器不识别C++的类作用域,该宏会在所有包含对应头文件的代码中全局生效,极易引发命名冲突。
- 宏展开后的代码和手动写
foo(__FUNCTION__, __FILE__, __LINE__)完全等价,访问私有成员失败的本质是:展开后的代码所在的作用域没有该类私有成员的访问权限。
方案1:兼容C++11/14/17的宏实现
场景1:宏仅在类内部成员函数中调用
直接把宏移到类外的头文件公开区域即可,类内部成员调用宏时天然有权限访问私有函数:
#include <string> using namespace std; // 宏定义放在类外,头文件公开区域 #define TEMP_FUNC() foo(__FUNCTION__, __FILE__, __LINE__) class Temp { private: void foo(string function, string file, int line) { // 自定义异常抛出等业务逻辑 } public: void test() { // 类内部调用宏,展开后有权限访问私有foo TEMP_FUNC(); } };
场景2:需要支持类外部通过宏调用
如果要允许外部代码通过宏调用私有逻辑,同时禁止用户直接调用处理函数,可以用公有接口+私有标签的技巧实现:
#include <string> using namespace std; // 对外公开的调用宏 #define TEMP_FUNC(obj) obj.foo(__FUNCTION__, __FILE__, __LINE__, {}) class Temp { private: // 私有标签类型,外部无法主动构造 struct PrivateTag {}; // 真正的业务实现,完全私有不对外暴露 void foo_impl(string function, string file, int line) { // 自定义异常抛出等业务逻辑 } public: // 公有重载接口,最后一个参数为私有标签,仅能通过宏传入空初始化构造 void foo(string function, string file, int line, PrivateTag) { foo_impl(function, file, line); } }; // 外部调用示例 int main() { Temp t; TEMP_FUNC(t); // 正常调用,宏自动补全所有参数 // 下方代码编译报错:PrivateTag是私有类型,外部无法主动构造 // t.foo("test", "test.cpp", 10, {}); return 0; }
方案2:C++20及以上优雅实现(无需宏)
C++20引入的std::source_location专门用于获取调用点的位置信息,不需要依赖宏,也不存在权限访问问题,是目前的最优解:
#include <string> #include <source_location> using namespace std; class Temp { private: void foo_impl(string function, string file, int line) { // 自定义异常抛出等业务逻辑 } public: // 公开接口,默认参数自动获取调用点的位置信息 void foo(const source_location& loc = source_location::current()) { foo_impl(loc.function_name(), loc.file_name(), loc.line()); } }; // 调用示例 int main() { Temp t; t.foo(); // 不需要传任何参数,自动获取main函数的位置信息 return 0; }
内容的提问来源于stack exchange,提问作者Akshay
相关产品推荐
相关产品推荐

