operator==可通过MSVC编译但无法通过GCC/Clang,谁符合C++标准?
这段C++代码哪个编译器的行为符合标准?
你编写的代码中,MSVC可以编译通过,但GCC和Clang会报错,根据C++标准,GCC和Clang的行为是正确的,MSVC的处理不符合标准要求。
问题根源分析
问题出在E结构体内部的友元operator==模板声明上:
template<typename P> struct C{ template<typename T> struct E { template<typename U = P, typename V = T> friend bool operator==(const typename C<U>::template E<V>&, const typename C<U>::template E<V>&); }; }; int main() { C<int>::E<double> d1, d2; std::cout<<(d1==d2); //compiles with msvc but rejected in gcc and clang }
当你在main中调用d1 == d2时,编译器需要推导operator==的模板参数U和V,但函数参数中的typename C<U>::template E<V>属于C++标准定义的非推断上下文——编译器无法从传入的C<int>::E<double>对象反向推导出模板参数U和V,因为嵌套依赖类型的模板参数推导被标准禁止。
虽然你给U和V指定了默认值P和T,但在函数调用的模板参数推导阶段,默认参数并不会被使用(只有当显式省略模板参数时才会生效)。因此GCC和Clang会因无法推导模板参数而报错,这完全符合标准规定;而MSVC在这里做了非标准的扩展,允许使用默认参数完成推导,所以能编译通过。
修复示例
如果想让代码符合标准并在所有编译器上通过,可以调整友元函数的声明方式,让模板参数可以被正常推导,比如:
template<typename P> struct C{ template<typename T> struct E { // 改为非模板友元,绑定到当前实例化的C<P>::E<T> friend bool operator==(const E&, const E&) { return true; // 示例实现 } }; }; int main() { C<int>::E<double> d1, d2; std::cout << (d1 == d2); }
内容的提问来源于stack exchange,提问作者user19414420
相关产品推荐
相关产品推荐

