如何实现参数包按引用与指针传递,适配重载函数调用?
如何让模板函数同时支持引用和指针类型的重载函数调用
我需要调用CFoo类的两个静态write重载函数——一个接受const char&类型参数,另一个接受const char*类型参数。当前实现的OnFoo模板函数用了两个参数包,但只能支持其中一种调用场景:
- 当参数包定义为
const Args1*... a, const Args0&... b时,只能成功调用按引用传参的write; - 交换参数包顺序后,只能支持指针传参的
write调用。
想知道怎么修改代码,让两种调用都能生效,或者合并参数包同时支持引用和指针传参。
原代码框架
class CFoo { public: static void write(const char& a, const char& b, const char& c) { } static void write(const char* a, const char* b, const char* c) { } }; #define TYPE_FUNCTION const Args1*... a, const Args0&... b // 仅支持引用传参 // #define TYPE_FUNCTION const Args0&... a, const Args1*... b // 仅支持指针传参 template <class... Args0, class... Args1> void OnFoo(void (*func)(TYPE_FUNCTION), TYPE_FUNCTION) { } int main(int argc, char** argv) { OnFoo(&CFoo::write, '1', '1', '1'); // OnFoo(&CFoo::write, "1", "1", "1"); return 0; }
情况一:仅支持引用传参,指针传参报错
代码
class CFoo { public: static void write(const char& a, const char& b, const char& c) { } static void write(const char* a, const char* b, const char* c) { } }; #define TYPE_FUNCTION const Args1*... a, const Args0&... b // 仅支持引用传参 template <class... Args0, class... Args1> void OnFoo(void (*func)(TYPE_FUNCTION), TYPE_FUNCTION) { } int main(int argc, char** argv) { OnFoo(&CFoo::write, '1', '1', '1'); OnFoo(&CFoo::write, "1", "1", "1"); // 报错 return 0; }
错误信息
main.cpp: In function 'int main(int, char**)': main.cpp:24:38: error: no matching function for call to 'OnFoo(<unresolved overloaded function type>, const char [2], const char [2], const char [2])' 24 | OnFoo(&CFoo::write, "1", "1", "1"); | ^ main.cpp:17:48: note: candidate: 'template<class ... Args0, class ... Args1> void OnFoo(void (*)(const Args1* ..., const Args0& ...), const Args1* ..., const Args0& ...)' 17 | template <class... Args0, class... Args1> void OnFoo(void (*func)(TYPE_FUNCTION), TYPE_FUNCTION) | ^~~~~ main.cpp:17:48: note: template argument deduction/substitution failed: main.cpp:24:38: note: mismatched types 'const Args0&' and 'const char*' 24 | OnFoo(&CFoo::write, "1", "1", "1"); | ^ main.cpp:24:38: note: inconsistent parameter pack deduction with 'char' and 'char [2]'
情况二:仅支持指针传参,引用传参报错
代码
class CFoo { public: static void write(const char& a, const char& b, const char& c) { } static void write(const char* a, const char* b, const char* c) { } }; #define TYPE_FUNCTION const Args1&... a, const Args0*... b // 仅支持指针传参 template <class... Args0, class... Args1> void OnFoo(void (*func)(TYPE_FUNCTION), TYPE_FUNCTION) { } int main(int argc, char** argv) { OnFoo(&CFoo::write, '1', '1', '1'); // 报错 OnFoo(&CFoo::write, "1", "1", "1"); return 0; }
错误信息
main.cpp:23:42: error: no matching function for call to 'OnFoo(<unresolved overloaded function type>, char, char, char)' 23 | OnFoo(&CFoo::write, '1', '1', '1'); | ^ main.cpp:17:52: note: candidate: 'template<class ... Args0, class ... Args1> void OnFoo(void (*)(const Args1& ..., const Args0* ...), const Args1& ..., const Args0* ...)' 17 | template <class... Args0, class... Args1> void OnFoo(void (*func)(TYPE_FUNCTION), TYPE_FUNCTION) | ^~~~~ main.cpp:17:52: note: template argument deduction/substitution failed: main.cpp:23:42: note: mismatched types 'const Args0*' and 'const char&' 23 | OnFoo(&CFoo::write, '1', '1', '1'); | ^ main.cpp:23:42: note: mismatched types 'const Args0*' and 'char'
解决方案
问题根源在于你用了两个独立的参数包,强制把参数分成指针和引用两类,而重载函数的参数是统一类型(要么全是引用,要么全是指针),导致模板推导时无法匹配。以下是两种可行的修改方式:
方式一:单个参数包兼容所有类型(推荐)
直接合并参数包,让模板参数与目标函数的参数列表完全对应,编译器会自动推导正确的重载函数:
class CFoo { public: static void write(const char& a, const char& b, const char& c) { } static void write(const char* a, const char* b, const char* c) { } }; template <class... Args> void OnFoo(void (*func)(Args...), Args... args) { func(args...); // 这里可添加自定义逻辑 } int main(int argc, char** argv) { OnFoo(&CFoo::write, '1', '1', '1'); // 匹配引用版本 OnFoo(&CFoo::write, "1", "1", "1"); // 匹配指针版本 return 0; }
方式二:C++20概念约束(扩展场景)
如果需要明确区分引用/指针参数类型,可使用C++20的概念来约束模板:
#include <concepts> #include <type_traits> class CFoo { public: static void write(const char& a, const char& b, const char& c) { } static void write(const char* a, const char* b, const char* c) { } }; // 约束参数全为引用类型 template <class... Args> requires (std::is_reference_v<Args> && ...) void OnFoo(void (*func)(Args...), Args... args) { func(args...); } // 约束参数全为指针类型 template <class... Args> requires (std::is_pointer_v<std::remove_cvref_t<Args>> && ...) void OnFoo(void (*func)(Args...), Args... args) { func(args...); } int main(int argc, char** argv) { OnFoo(&CFoo::write, '1', '1', '1'); OnFoo(&CFoo::write, "1", "1", "1"); return 0; }
这种方式适合有特殊类型校验需求的场景,普通场景下方式一的通用性更强。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

