C++模板区分数据成员与成员函数指针特化在GCC11报错咨询
问题原因
该问题是GCC 11+版本的模板偏特化偏序规则实现bug,符合C++17标准的原代码本应正常编译:按照标准要求,指向成员函数的指针特化比通用成员指针特化更具体,应该被优先匹配,旧版GCC和Clang的行为符合标准规范。
GCC 11+出现二义性的原因是它错误地将成员函数指针同时匹配到两个偏特化:第一个特化中的K被推导为函数类型int(),使得K V::*F也能匹配成员函数指针,且GCC没有正确识别第二个特化的更特殊性。
最简单的兼容解决方案
只需要给指向数据成员的偏特化增加约束,限制K不能为函数类型即可,修改后代码可同时兼容所有版本GCC、Clang、MSVC,且对原有业务逻辑侵入性最小。
如果使用C++20及以上标准,可直接用requires约束:
#include <iostream> #include <type_traits> template<auto F> struct which; template<typename K, typename V, K V::*F> requires (!std::is_function_v<K>) struct which<F> { static constexpr char desc[] = "pointer to data member"; }; template<typename K, typename V, K (V::*F)()> struct which<F> { static constexpr char desc[] = "pointer to member function"; }; struct S { int i; int f() { return 0; } }; int main() { std::cout << "S::i: " << which<&S::i>::desc << std::endl; std::cout << "S::f: " << which<&S::f>::desc << std::endl; }
如果需要兼容C++17标准,可改用SFINAE方式实现约束:
template<typename K, typename V, K V::*F, typename = std::enable_if_t<!std::is_function_v<K>>> struct which<F> { static constexpr char desc[] = "pointer to data member"; };
修改后成员函数指针不会再匹配到数据成员特化,二义性问题完全解决。
内容的提问来源于stack exchange,提问作者user3188445
相关产品推荐
相关产品推荐

