VS2022 17.6前后兼容的C++ Property类比较代码改写咨询
问题描述
以下代码在VS 2022 17.6及之后版本无法编译,但可在最新g++中编译。需要改写代码,使其在VS2022 17.6前后版本均能正常编译。
代码示例:
template<class T> struct Property { operator const T&() const { return value; } bool operator==(const T &val) const { return this->value == val; } bool operator!=(const T &val) const { return this->value != val; } T value; }; int main() { enum class Foo {Red, Green}; Property<Foo> a; Foo e; bool comp2 = e == a; bool comp3 = e != a; }
注:交换操作数顺序(如a == e)可正常编译,但需要通用的代码改写方案。
解决方案
方法1:添加非成员比较运算符
为Property<T>补充全局的==和!=非成员运算符,让编译器在处理e == a这类左操作数为T、右操作数为Property<T>的表达式时,能直接匹配到合适的重载:
template<class T> struct Property { operator const T&() const { return value; } bool operator==(const T &val) const { return this->value == val; } bool operator!=(const T &val) const { return this->value != val; } T value; }; // 补充左操作数为T、右操作数为Property<T>的比较运算符 template<class T> bool operator==(const T& lhs, const Property<T>& rhs) { return lhs == static_cast<const T&>(rhs); } template<class T> bool operator!=(const T& lhs, const Property<T>& rhs) { return !(lhs == rhs); } int main() { enum class Foo {Red, Green}; Property<Foo> a; Foo e; bool comp2 = e == a; // 可正常编译 bool comp3 = e != a; // 可正常编译 }
方法2:成员运算符模板化(兼容C++11及以上)
如果不想添加全局运算符,也可以在Property结构体内部添加模板化的比较成员,匹配任意可与T比较的类型,包括T本身:
template<class T> struct Property { operator const T&() const { return value; } // 模板化的==运算符,匹配任意可与T比较的类型U template<class U> bool operator==(const U& val) const { return value == val; } template<class U> bool operator!=(const U& val) const { return value != val; } T value; }; int main() { enum class Foo {Red, Green}; Property<Foo> a; Foo e; bool comp2 = e == a; // 可正常编译 bool comp3 = e != a; // 可正常编译 }
原理说明
VS 2022 17.6及之后版本对重载决议中的隐式转换优先级做了更严格的限制。当处理e == a时,编译器不会自动将a隐式转换为T后调用enum class的内置比较运算符。通过补充反向匹配的运算符重载,或者将成员运算符改为模板化,让编译器能直接找到符合参数类型的重载,避免了依赖隐式转换的重载决议冲突。
内容的提问来源于stack exchange,提问作者Michiel Jaspers
相关产品推荐
相关产品推荐

