C++如何单语句声明成员函数指针?或生成调用B成员的宏?
问题与解答
原代码背景
以下是用于衔接通用算法与外部生成类(以B为例)的代码:
// 外部生成的类 struct B { void foo(int); void foo(); int bar(); int bar() const; float blah(int) const; }; #define DECLARE_METHOD_TYPE(TName, CName, Func) \ template<typename ...Args> \ using TName = decltype( \ std::declval<CName>().Func(std::declval<Args>() ...)) \ (CName::*) (Args...) #define METHOD_PTR(TName, ... ) static constexpr TName<__VA_ARGS__> // 桥接类 struct A { DECLARE_METHOD_TYPE(FooPtr, B, foo); // 需要分别声明两种版本 DECLARE_METHOD_TYPE(BarPtr, B, bar); DECLARE_METHOD_TYPE(BarPtrConst, B, bar) const; // 必须是const版本 DECLARE_METHOD_TYPE(BlahPtrConst, B, blah) const; METHOD_PTR(FooPtr, int) b_foo_n = &B::foo; METHOD_PTR(FooPtr) b_foo = &B::foo; METHOD_PTR(BarPtr) b_bar = &B::bar; METHOD_PTR(BarPtrConst) b_cbar = &B::bar; // 必须严格匹配参数 METHOD_PTR(BlahPtrConst, int) b_blah = &B::blah; };
核心问题
- 当前实现中每个成员函数指针需要先声明类型再定义指针,能否用单语句完成每个指针的声明?核心难点在于指针类型是模板,需要唯一类型名。
- 能否创建宏来生成调用
B类成员的成员函数(类似访问者模式)?目前可以声明这类函数,但无法完成定义。
解答
1. 单语句完成成员函数指针声明
可以通过合并宏逻辑,直接在定义指针的同时推导并生成类型,不需要单独的DECLARE_METHOD_TYPE步骤。核心思路是利用decltype推导成员函数的类型,结合宏的命名隔离技巧:
#include <utility> // 外部生成的类 struct B { void foo(int); void foo(); int bar(); int bar() const; float blah(int) const; }; // 合并类型声明与指针定义的宏(非const成员) #define DEFINE_METHOD_PTR(VarName, CName, Func, ...) \ template<typename... Args> \ using _##VarName##_type = decltype(std::declval<CName>().Func(std::declval<Args>()...)) (CName::*)(Args...); \ static constexpr _##VarName##_type<__VA_ARGS__> VarName = &CName::Func; // 处理const成员函数的版本 #define DEFINE_CONST_METHOD_PTR(VarName, CName, Func, ...) \ template<typename... Args> \ using _##VarName##_type = decltype(std::declval<const CName>().Func(std::declval<Args>()...)) (const CName::*)(Args...); \ static constexpr _##VarName##_type<__VA_ARGS__> VarName = &CName::Func; // 桥接类 struct A { // 非const成员函数,带参数 DEFINE_METHOD_PTR(b_foo_n, B, foo, int) // 非const成员函数,无参数 DEFINE_METHOD_PTR(b_foo, B, foo) // 非const版bar DEFINE_METHOD_PTR(b_bar, B, bar) // const版bar DEFINE_CONST_METHOD_PTR(b_cbar, B, bar) // const版blah,带参数 DEFINE_CONST_METHOD_PTR(b_blah, B, blah, int) };
这里通过下划线前缀的模板别名(_##VarName##_type)避免命名冲突,在宏内部隐式完成类型声明,最终实现单语句完成指针的声明与定义。
2. 宏生成调用B类成员的访问者函数
可以创建宏自动生成A中调用B成员的函数,需要处理返回值、参数列表、const修饰符三种核心情况。假设A持有B的指针或引用(如B* b;),宏设计如下:
手动指定返回值版本
#include <utility> // 外部生成的类 struct B { void foo(int); void foo(); int bar(); int bar() const; float blah(int) const; }; // 生成非const访问函数 #define GENERATE_VISITOR_FUNC(RetType, FuncName, ...) \ RetType FuncName(__VA_ARGS__) { \ return b->FuncName(__VA_ARGS__); \ } // 生成const访问函数 #define GENERATE_CONST_VISITOR_FUNC(RetType, FuncName, ...) \ RetType FuncName(__VA_ARGS__) const { \ return b->FuncName(__VA_ARGS__); \ } // 桥接类 struct A { B* b; // 持有B的指针 // 生成foo的两个版本 GENERATE_VISITOR_FUNC(void, foo, int x) GENERATE_VISITOR_FUNC(void, foo) // 生成bar的非const版本 GENERATE_VISITOR_FUNC(int, bar) // 生成bar的const版本 GENERATE_CONST_VISITOR_FUNC(int, bar) // 生成blah的const版本 GENERATE_CONST_VISITOR_FUNC(float, blah, int x) };
自动推导返回值版本(C++14及以上)
如果不想手动指定返回值,可结合auto返回值推导进一步简化:
// 自动推导返回值的非const访问宏 #define GENERATE_AUTO_VISITOR_FUNC(FuncName, ...) \ auto FuncName(__VA_ARGS__) { \ return b->FuncName(__VA_ARGS__); \ } // 自动推导返回值的const访问宏 #define GENERATE_AUTO_CONST_VISITOR_FUNC(FuncName, ...) \ auto FuncName(__VA_ARGS__) const { \ return b->FuncName(__VA_ARGS__); \ } struct A { B* b; GENERATE_AUTO_VISITOR_FUNC(foo, int x) GENERATE_AUTO_VISITOR_FUNC(foo) GENERATE_AUTO_VISITOR_FUNC(bar) GENERATE_AUTO_CONST_VISITOR_FUNC(bar) GENERATE_AUTO_CONST_VISITOR_FUNC(blah, int x) };
这种方式无需手动匹配返回值,宏会自动适配B类成员函数的签名。
内容的提问来源于stack exchange,提问作者Swift - Friday Pie
相关产品推荐
相关产品推荐

