C++20特定模板特化友元声明的跨编译器兼容问题
关于C++20模板特化友元声明的跨编译器兼容与标准合规性问题
1. 跨编译器兼容的解决方案
要让该模板特化的友元声明兼容所有编译器,核心是提前声明函数模板fun2,让编译器在处理友元声明时能明确识别fun2是模板,进而解析fun2<T>为特化。修改后的代码如下:
// 提前声明Ext模板,因为fun2的参数依赖Ext<T>::Inner template <class T> struct Ext; // 提前声明fun2函数模板 template <class T> void fun2(typename Ext<T>::Inner &p); template <class T> struct Ext { struct Inner { int m{}; }; // 此时编译器已明确fun2是模板,能正确识别该特化声明 friend void fun2<T>(typename Ext<T>::Inner&); }; template <class T> void fun2(typename Ext<T>::Inner &p) { p.m = 10; } int main() { Ext<int>::Inner x; fun2<int>(x); }
这段代码可以在GCC、MSVC和Clang中正常编译运行。
2. 原代码在C++20中的合规性
原代码不属于C++20标准下的良构代码。
根据C++标准的[temp.friend]条款,当声明依赖类型的友元函数模板特化时,必须提前存在对应的函数模板声明。原代码中,在Ext<T>的友元声明处,fun2还未被声明为模板,编译器无法确定fun2<T>是模板特化还是普通函数调用,因此不符合标准要求。
Clang的报错是严格遵循标准的行为,而GCC和MSVC在此处做了非标准的宽松处理,允许未提前声明模板的情况下解析该特化。
内容的提问来源于stack exchange,提问作者user20562802
相关产品推荐
相关产品推荐

