资讯动态

c++ 拆分函数返回值和参数类型

发布时间:2026/8/20 15:26:02 来源:尧图企业网站定制
在c中函数参数类型和返回值类型通常是一个比较明确的信息好像确实无需在这个上面费周折。然而硬编码数据类型会让代码复用性下降如果能够通过某种方式自动获取函数参数和返回值类型对于代码的可复用性可读性和整洁性都有较大的提升。最近阅读GoogleTest的源码(v1.8.1)发现它采用了模板方法实现了这一点// googletest/googlemock/include/gmock/internal /gmock-generated-internal-utils.h ... template typename F struct Function; template typename R struct FunctionR() { typedef R Result; ... }; template typename R, typename A1 struct FunctionR(A1): FunctionR() { typedef A1 Argument1; ... }; template typename R, typename A1, typename A2 struct FunctionR(A1, A2): FunctionR(A1) { typedef A2 Argument2; ... }; template typename R, typename A1, typename A2, typename A3 struct FunctionR(A1, A2, A3): FunctionR(A1, A2) { typedef A3 Argument3; ... }; ...上面的代码gmock在使用的时候是配合宏实现不同类型函数的统一。在实际开发中我们可以借助decltypeauto以及函数指针的方式来对函数的返回值和参数类型进行统一拆分对上述代码进行稍微调整以便适配具有不同调用方式的函数template typename T struct Function; //以下以__stdcall 调用类型为例如果函数调用类型是 __cdcel, 则需要特化新的模板组 template typename R struct FunctionR(__stdcall*)() { typedef R RESULT; }; template typename R, typename A1 struct FunctionR(__stdcall*)(A1) :FunctionR(__stdcall*)() { typedef A1 ARG1; }; template typename R, typename A1, typename A2 struct FunctionR(__stdcall*)(A1, A2) :FunctionR(__stdcall*)(A1) { typedef A2 ARG2; }; template typename R, typename A1, typename A2, typename A3 struct FunctionR(__stdcall*)(A1, A2, A3) :FunctionR(__stdcall*)(A1, A2) { typedef A3 ARG3; }; // 如果有更多参数可在此处扩展测试代码int __stdcall STD_CALL_FUNC_WITH_ONE_PARAM(int b) { int nn 0; return nn; } templatetypename Rtn, typename... Args Rtn StdMethodExec(void* f, Args... args) { using Func Rtn(__stdcall*)(Args...); Func tFunc (Func)f; /*doing some work...*/ Rtn ret tFunc(std::forwardArgs(args)...); return ret; } int main(int argc, char* argv[], char* env[]) { //typedef int (__stdcall *Func)(int); using Func decltype(STD_CALL_FUNC_WITH_ONE_PARAM); Func bvn STD_CALL_FUNC_WITH_ONE_PARAM; Functiondecltype(bvn)::RESULT result1; Functiondecltype(bvn)::ARG1 arg1; auto funcAutoPtr STD_CALL_FUNC_WITH_ONE_PARAM; Functiondecltype(funcAutoPtr)::RESULT result2; Functiondecltype(funcAutoPtr)::ARG1 arg2; FunctionFunc::RESULT result3; Functiondecltype(STD_CALL_FUNC_WITH_ONE_PARAM)::ARG1 arg3; auto ret StdMethodExecint(STD_CALL_FUNC_WITH_ONE_PARAM, 5); return 0; }利用SFINAE实现信号槽//Trits.h #pragma once //////////////////////////////////////////////基础设施类型列表/////////////////////////////////////////////// namespace T1 { templatetypename... struct List {}; templatetypename Head, typename... Tail struct ListHead, Tail... { typedef Head Car; typedef ListTail... Cdr; }; // 列表长度 templatetypename L struct ListSize; template struct ListSizeList { enum { value 0 }; }; templatetypename H, typename... T struct ListSizeListH, T... { enum { value 1 ListSizeListT... ::value }; }; // 取第 N 个类型 templatetypename L, int N struct ListAt { typedef typename ListAttypename L::Cdr, N - 1::Type Type; }; templatetypename L struct ListAtL, 0 { typedef typename L::Car Type; }; // 示例 // typedef Listint, double, char MyList; // static_assert(ListSizeMyList::value 3, ); // static_assert(std::is_sameListAtMyList, 1::Type, double::value, ); // 内部辅助检查类型是否相同替代 std::is_same templatetypename T, typename U struct IsSame { enum { value false }; }; templatetypename T struct IsSameT, T { enum { value true }; }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////索引序列//////////////////////////////////////////////////////// templateint... Is struct IndexSeq {}; // 生成 IndexSeq0,1,2,...,N-1 templateint N, int... Is struct MakeIndexSeq : MakeIndexSeqN - 1, N - 1, Is... {}; templateint... Is struct MakeIndexSeq0, Is... { typedef IndexSeqIs... Type; }; // 示例 // MakeIndexSeq3::Type IndexSeq0, 1, 2 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////函数签名分解//////////////////////////////////////////////////// // ---- 去除引用和 const ---- templatetypename T struct RemoveRef { typedef T Type; }; templatetypename T struct RemoveRefT { typedef T Type; }; templatetypename T struct RemoveRefT { typedef T Type; }; templatetypename T struct RemoveConst { typedef T Type; }; templatetypename T struct RemoveConstconst T { typedef T Type; }; // ---- 函数指针特征提取 ---- templatetypename T struct FuncTraits { enum { ArgCount -1, IsMemberFunction false }; }; // 普通函数指针 templatetypename R, typename... Args struct FuncTraitsR(*)(Args...) { typedef R ReturnType; typedef ListArgs... Arguments; enum { ArgCount sizeof...(Args), IsMemberFunction false }; }; // 类成员函数 templatetypename R, typename C, typename... Args struct FuncTraitsR(C::*)(Args...) { typedef C ClassType; typedef R ReturnType; typedef ListArgs... Arguments; enum { ArgCount sizeof...(Args), IsMemberFunction true }; }; // const 成员函数 templatetypename R, typename C, typename... Args struct FuncTraitsR(C::*)(Args...) const { typedef C ClassType; typedef R ReturnType; typedef ListArgs... Arguments; enum { ArgCount sizeof...(Args), IsMemberFunction true }; }; // 示例 // struct Calculator { int calculate(double d, char c) const { return (int)d c; } }; // typedef FuncTraitsdecltype(Calculator::calculate) T; // static_assert(T::ArgCount 2, ); // static_assert(T::IsMemberFunction true, ); // static_assert(std::is_sameT::ReturnType, int::value, ); // static_assert(std::is_sameT::ClassType, Calculator::value, ); // static_assert(std::is_sameListAtT::Arguments, 0::Type, double::value, ); ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////编译期参数兼容性检查///////////////////////////////////////////// // 检查 From 能否隐式转换为 To templatetypename From, typename To struct CanConvert { static int test(const To); static char test(...); static const From dummy(); enum { value sizeof(test(dummy())) sizeof(int) }; }; // void 特殊处理void 和任何类型兼容 templatetypename T struct CanConvertvoid, T { enum { value true }; }; templatetypename T struct CanConvertT, void { enum { value true }; }; template struct CanConvertvoid, void { enum { value true }; }; // 递归检查两个参数列表是否兼容 templatetypename SigList, typename SlotList struct ArgsCompatible { enum { value false }; }; templatetypename SigList struct ArgsCompatibleSigList, List { enum { value true }; }; template struct ArgsCompatibleList, List { enum { value true }; }; // 逐对检查 templatetypename S1, typename... ST, typename L1, typename... LT struct ArgsCompatibleListS1, ST..., ListL1, LT... { enum { value CanConvertS1, L1::value ArgsCompatibleListST..., ListLT... ::value }; }; // 示例 // static_assert(ArgsCompatibleListint, double, const char*, Listlong, float::value, ); // static_assert(ArgsCompatibleListint, double, Listlong, std::string ::value false, ); ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////void** 参数展开调用函数////////////////////////////////////////// // 调用成员函数保留作为工具CSignal 内部也可直接使用 templateint... II, typename R, typename C, typename... SlotArgs, typename... SigArgs void callMember(R(C::* func)(SlotArgs...), C* obj, void** args, IndexSeqII..., ListSigArgs...) { (obj-*func)(*reinterpret_casttypename RemoveRefSigArgs::Type*(args[II 1])...); // args[0] 留给返回值实际参数从 args[1] 开始 } // 调用普通函数/lambda注意这里假设 func 是函数指针若为 lambda 需另处理 templateint... II, typename F, typename... SigArgs void callFunc(F func, void** args, IndexSeqII..., ListSigArgs...) { func(*reinterpret_casttypename RemoveRefSigArgs::Type*(args[II 1])...); } // 示例 // struct Calculator { int add(int a, int b) { return a b; } }; // Calculator calc; // int v1 3, v2 5; // void* args[] { nullptr, v1, v2 }; // callMember(Calculator::add, calc, args, // typename MakeIndexSeq2::Type(), // IndexSeq0, 1 // Listint, int()); // 参数类型列表 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////信号槽系统CSignal///////////////////////////////////////////// templatetypename... SigArgs class CSignal { // 类型擦除的槽基类 struct SlotBase { virtual ~SlotBase() {} virtual void call(void** args) 0; }; // ----- 特化1普通函数 / 静态函数 ----- templatetypename Func, int N struct SlotImplStatic : SlotBase { Func func; SlotImplStatic(Func f) : func(f) {} void call(void** args) override { callExpand(args, typename MakeIndexSeqN::Type()); } templateint... II void callExpand(void** args, IndexSeqII...) { // 从 args[1] 开始取 N 个参数并转换为对应类型 func(*reinterpret_casttypename RemoveRefSigArgs::Type*(args[II 1])...); } }; // ----- 特化2成员函数额外存储对象指针----- templatetypename Func, typename Class, int N struct SlotImplMember : SlotBase { Func func; Class* obj; SlotImplMember(Func f, Class* o) : func(f), obj(o) {} void call(void** args) override { callExpand(args, typename MakeIndexSeqN::Type()); } templateint... II void callExpand(void** args, IndexSeqII...) { (obj-*func)(*reinterpret_casttypename RemoveRefSigArgs::Type*(args[II 1])...); } }; std::vectorSlotBase* slotList; public: ~CSignal() { typename std::vectorSlotBase*::iterator it slotList.begin(); for (; it ! slotList.end(); it) delete *it; } // ----- 连接普通函数 / 静态函数 ----- templatetypename F void CSconnect(F f) { typedef FuncTraitsF Traits; static_assert(!Traits::IsMemberFunction, 成员函数请使用 CSconnect(func, obj) 重载); enum { N Traits::ArgCount }; static_assert(N sizeof...(SigArgs), 槽参数过多); // 检查参数类型兼容性槽参数要能隐式转换为信号的前 N 个参数 static_assert(ArgsCompatibletypename Traits::Arguments, ListSigArgs... ::value, 参数类型不兼容); slotList.push_back(new SlotImplStaticF, N(f)); } // ----- 连接成员函数 ----- templatetypename F, typename C void CSconnect(F f, C* obj) { typedef FuncTraitsF Traits; static_assert(Traits::IsMemberFunction, 非成员函数请使用 CSconnect(func) 重载); static_assert(IsSameC, typename Traits::ClassType::value, 对象类型与成员函数所属类不匹配); enum { N Traits::ArgCount }; static_assert(N sizeof...(SigArgs), 槽参数过多); static_assert(ArgsCompatibletypename Traits::Arguments, ListSigArgs... ::value, 参数类型不兼容); slotList.push_back(new SlotImplMemberF, C, N(f, obj)); } // ----- 发射信号 ----- void CSemit(SigArgs... args) { // 使用数组存储参数指针 void* argArray[] { nullptr, reinterpret_castvoid*(args)... }; typename std::vectorSlotBase*::iterator it slotList.begin(); for (;it ! slotList.end();it) (*it)-call(argArray); } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// }; //main.cpp #include chrono #include iostream #include string #include functional #include vector #include iostream #include Trits.h struct MyClass { // 静态函数 static void staticFunc(int a, double b) { std::cout staticFunc: a std::endl; } // 成员函数 void memberFunc(int a, double b) const { std::cout memberFunc: a , b std::endl; } }; int main(int argc, char* argv[], char* env[]) { // 测试自定义信号系统 T1::CSignalint, double sig; // 连接静态函数 sig.CSconnect(MyClass::staticFunc); // 连接成员函数 MyClass obj; sig.CSconnect(MyClass::memberFunc, obj); // 发射信号 sig.CSemit(42, 3.14); return 0; }支持lambda返回类型推导要用到编译器尾置返回类型推导和decltype内部触发SFINAE的能力必须完整支持C11才行(VS的工具集版本号大于等于v141)//Trits.h #pragma once namespace T2 { //////////////////////////////////////////////基础设施类型列表/////////////////////////////////////////////// templatetypename... struct List {}; templatetypename Head, typename... Tail struct ListHead, Tail... { typedef Head Car; typedef ListTail... Cdr; }; // 列表长度 templatetypename L struct ListSize; template struct ListSizeList { enum { value 0 }; }; templatetypename H, typename... T struct ListSizeListH, T... { enum { value 1 ListSizeListT...::value }; }; // 取第 N 个类型 templatetypename L, int N struct ListAt { typedef typename ListAttypename L::Cdr, N - 1::Type Type; }; templatetypename L struct ListAtL, 0 { typedef typename L::Car Type; }; //e.g: //typedef Listint, double, char MyList; //static_assert(ListSizeMyList::value 3, ); //static_assert(std::is_sameListAtMyList, 1::Type, double::value, ); ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////索引序列//////////////////////////////////////////////////////// // ---- 索引序列 ---- templateint... Is struct IndexSeq {}; // 生成 IndexSeq0,1,2,...,N-1 templateint N, int... Is struct MakeIndexSeq : MakeIndexSeqN - 1, N - 1, Is... { }; templateint... Is struct MakeIndexSeq0, Is... { typedef IndexSeqIs... Type; }; //e.g: //MakeIndexSeq3::Type IndexSeq0, 1, 2 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////函数签名分解//////////////////////////////////////////////////// // ---- 去除引用和 const ---- templatetypename T struct RemoveRef { typedef T Type; }; templatetypename T struct RemoveRefT { typedef T Type; }; templatetypename T struct RemoveRefT { typedef T Type; }; templatetypename T struct RemoveConst { typedef T Type; }; templatetypename T struct RemoveConstconst T { typedef T Type; }; // ---- 函数指针特征提取 ---- templatetypename T struct FuncTraits { enum { ArgCount -1, IsMemberFunction false }; }; // 普通函数指针 templatetypename R, typename... Args struct FuncTraitsR(*)(Args...) { typedef R ReturnType; typedef ListArgs... Arguments; enum { ArgCount sizeof...(Args), IsMemberFunction false }; }; // 类成员函数 templatetypename R, typename C, typename... Args struct FuncTraitsR(C::*)(Args...) { typedef C ClassType; typedef R ReturnType; typedef ListArgs... Arguments; enum { ArgCount sizeof...(Args), IsMemberFunction true }; }; // const 成员函数 templatetypename R, typename C, typename... Args struct FuncTraitsR(C::*)(Args...) const { typedef C ClassType; typedef R ReturnType; typedef ListArgs... Arguments; enum { ArgCount sizeof...(Args), IsMemberFunction true }; }; //e.g //struct Calculator {int calculate(double d, char c) const { return (int)d c; }}; //typedef FuncTraitsdecltype(Calculator::calculate) T; //static_assert(T::ArgCount 2, ); //static_assert(T::IsMemberFunction true, ); //static_assert(std::is_sameT::ReturnType, int::value, ); //static_assert(std::is_sameT::ClassType, Calculator::value, ); //static_assert(std::is_sameListAtT::Arguments, 0::Type, double::value, ); ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////编译期参数兼容性检查///////////////////////////////////////////// // 检查 From 能否隐式转换为 To templatetypename From, typename To struct CanConvert { static int test(const To); static char test(...); static const From dummy(); enum { value sizeof(test(dummy())) sizeof(int) }; }; // void 特殊处理void 和任何类型兼容 templatetypename T struct CanConvertvoid, T { enum { value true }; }; templatetypename T struct CanConvertT, void { enum { value true }; }; template struct CanConvertvoid, void { enum { value true }; }; // 递归检查两个参数列表是否兼容 templatetypename SigList, typename SlotList struct ArgsCompatible { enum { value false }; }; templatetypename SigList struct ArgsCompatibleSigList, List { enum { value true }; }; template struct ArgsCompatibleList, List { enum { value true }; }; // 逐对检查 templatetypename S1, typename... ST, typename L1, typename... LT struct ArgsCompatibleListS1, ST..., ListL1, LT... { enum { value CanConvertS1, L1::value ArgsCompatibleListST..., ListLT...::value }; }; //e.g //static_assert(ArgsCompatibleListint, double, const char*, Listlong, float::value, ); //static_assert(ArgsCompatibleListint, double, Listlong, std::string::value false, ); ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////void** 参数展开调用函数////////////////////////////////////////// // 调用成员函数 templateint... II, typename R, typename C, typename... SlotArgs, typename... SigArgs void callMember(R(C::* func)(SlotArgs...), C* obj, void** args, IndexSeqII..., ListSigArgs...) { (obj-*func)(*reinterpret_casttypename RemoveRefSigArgs::Type*(args[II 1])...); // args[0] 留给返回值实际参数从 args[1] 开始 } // 调用普通函数/lambda templateint... II, typename F, typename... SigArgs void callFunc(F func, void** args, IndexSeqII..., ListSigArgs...) { func(*reinterpret_casttypename RemoveRefSigArgs::Type*(args[II 1])...); } //e.g //struct Calculator {int add(int a, int b) { return a b; } }; //Calculator calc; //int v1 3, v2 5; //void* args[] { nullptr, v1, v2 }; //callMember(Calculator::add, calc, args, // typename MakeIndexSeq2::Type(), // IndexSeq0, 1 // Listint, int());//参数类型列表 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////探测 lambda/functor 接受几个参数////////////////////////////////// // 辅助List_Prepend templatetypename H, typename L struct ListPrepend; templatetypename H, typename... T struct ListPrependH, ListT... { typedef ListH, T... Type; }; templatetypename L, int N struct ListTake { typedef typename ListPrependtypename L::Car, typename ListTaketypename L::Cdr, N - 1::Type::Type Type; }; templatetypename L struct ListTakeL, 0 { typedef List Type; }; // ---- SFINAE 探测 functor 是否能接收 N 个参数 ---- // 特化展开 ListArgs... 来尝试调用 templatetypename F, typename ArgList struct CanCallWith; templatetypename F, typename... Args struct CanCallWithF, ListArgs... { templatetypename G static auto test(int) - decltype(std::declvalG()(std::declvalArgs()...), int());//要求完整的C11 SFINAE templatetypename G static char test(long); enum { value sizeof(testF(0)) sizeof(int) }; }; // 递归递减参数个数 templatetypename F, typename ArgList, bool Ok struct ProbeHelper { enum { value -1 }; }; // 默认不匹配 templatetypename F, typename ArgList struct ProbeHelperF, ArgList, true { enum { value ListSizeArgList::value }; }; templatetypename F, typename... Args struct ProbeHelperF, ListArgs..., false : ProbeHelperF, typename ListTakeListArgs..., sizeof...(Args) - 1::Type, CanCallWithF, typename ListTakeListArgs..., sizeof...(Args) - 1::Type::value { }; templatetypename F, typename SigArgList struct DetectFunctorArgs { enum { value ProbeHelperF, SigArgList, CanCallWithF, SigArgList::value::value }; }; //e.g: //typedef Listint, double, const char* SigArgs; //auto lambda3 [](int a, double b, const char* c) {}; //auto lambda2 [](int a, double b) {}; //auto lambda0 []() {}; //// lambda3 接受 3 个参数 //static_assert(DetectFunctorArgsdecltype(lambda3), SigArgs::value 3, ); //// lambda2 接受 2 个参数从 3 个开始试探发现不行降到 2 个成功 //static_assert(DetectFunctorArgsdecltype(lambda2), SigArgs::value 2, ); //// lambda0 接受 0 个参数 //static_assert(DetectFunctorArgsdecltype(lambda0), SigArgs::value 0, ) ///////////////////////////////////////////////////////////////////////////////////////////////////////////// templatetypename... SigArgs class CSignal { // 类型擦除的槽基类 struct SlotBase { virtual ~SlotBase() {} virtual void call(void** args) 0; }; // 具体槽实现 templatetypename Func, int N struct SlotImpl : SlotBase { Func func; SlotImpl(Func f) : func(f) {} void call(void** args) { callHelper(args, typename MakeIndexSeqN::Type()); } templateint... II void callHelper(void** args, IndexSeqII...) { typedef typename ListTakeListSigArgs..., N::Type TakeArgs; callExpanded(args, TakeArgs(), IndexSeqII...()); } templatetypename... A, int... II void callExpanded(void** args, ListA..., IndexSeqII...) { func(*reinterpret_casttypename RemoveRefA::Type*(args[II 1])...); } }; std::vectorSlotBase* slotList; public: ~CSignal() { typename std::vectorSlotBase*::iterator it slotList.begin(); for (; it ! slotList.end(); it) delete *it; } templatetypename F void CSconnect(F f) { enum { N DetectFunctorArgsF, ListSigArgs...::value }; static_assert(N 0, Functor arguments dont match signal);//编译期检查参数兼容性 slotList.push_back(new SlotImplF, N(f)); } void CSemit(SigArgs... args) { // 使用数组存储参数指针 void* argArray[] { nullptr, reinterpret_castvoid*(args)... }; typename std::vectorSlotBase*::iterator it slotList.begin(); for (; it ! slotList.end(); it) (*it)-call(argArray); } }; }; //main.cpp #include chrono #include iostream #include string #include functional #include iostream #include vector #include Trits.h int main(int argc, char* argv[], char* env[]) { // 测试自定义信号系统 T2::CSignalint, double sig; // 接受全部参数 sig.CSconnect([](int a, double b) { std::cout all: a b std::endl; }); // 只接受部分参数 sig.CSconnect([](int a) { std::cout partial: a std::endl; }); // 不接受参数 sig.CSconnect([]() { std::cout none std::endl; }); sig.CSemit(42, 3.14); return 0; }

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价