C++编译期检测:调用S::f(int)是否匹配非模板成员函数?
编译期检测调用
f(int)时是否匹配模板成员函数 针对你的需求,我们可以利用C++重载决议的优先级以及编译期函数指针比较的特性,实现对应的编译期检测。
C++17 实现方案
核心思路:当类中存在普通的void f(int)成员函数时,取&S::f会优先指向该普通函数;而模板实例化的&S::f<int>指向的是模板生成的函数,二者地址不同。若不存在普通函数,则&S::f等价于&S::f<int>,地址相同。基于此可以编写检测 trait:
#include <type_traits> template <typename Class> struct is_f_int_calls_template { // 编译期比较重载决议选中的函数与模板实例化函数的地址 static constexpr bool value = (&Class::f == &Class::f<int>); }; // 辅助变量模板,简化使用 template <typename Class> inline constexpr bool is_f_int_calls_template_v = is_f_int_calls_template<Class>::value;
使用示例
struct S { void f(int) {} // 普通成员函数 template <class T> void f(T) {} // 模板成员函数 }; struct S_NoNonTemplate { template <class T> void f(T) {} // 仅模板成员函数 }; // 检测结果:存在普通函数,返回 false static_assert(!is_f_int_calls_template_v<S>); // 检测结果:无普通函数,返回 true static_assert(is_f_int_calls_template_v<S_NoNonTemplate>);
C++20 简化方案(Concepts)
利用C++20的Concepts特性,可以写出更简洁的约束:
template <typename Class> concept CallsTemplateFInt = (&Class::f == &Class::f<int>);
使用示例
// 编译期分支判断 if constexpr (CallsTemplateFInt<S>) { // 匹配模板函数的逻辑 } else { // 匹配普通函数的逻辑 }
原理说明
- 重载决议优先级:在同名函数匹配时,非模板函数的优先级高于模板函数,因此
&Class::f会优先指向普通的void f(int)(如果存在); - 编译期函数指针比较:C++11及以后支持编译期比较函数指针的相等性,通过对比
&Class::f和&Class::f<int>的地址,即可判断调用f(int)时是否匹配模板函数。
内容的提问来源于stack exchange,提问作者αλεχολυτ
相关产品推荐
相关产品推荐

