未能 select 使用 MSVC 更正 operator== 但不是 gcc/clang 模板 class
Failure to select correct operator== with MSVC but not gcc/clang for templated class
以下示例使用 gcc 和 clang 编译良好,但无法在 MSVC 中编译。我想知道我是否无意中跌入了非标准领域?如果不是,哪个编译器是正确的?是否有解决方法?
最小示例 (https://godbolt.org/z/PG35hPGMW):
#include <iostream>
#include <type_traits>
template <class T>
struct Base {
Base() = default;
Base(T) {}
static constexpr bool isBase = true;
};
template <class U>
constexpr std::enable_if_t<U::isBase, bool> EnableComparisonWithValue(U const *) {
return false;
}
template <class>
constexpr bool EnableComparisonWithValue(...) {
return true;
}
template <class T, class U>
bool operator==(Base<T> const &, Base<U> const &) {
std::cout << "operator==(Base, Base)" << std::endl;
return true;
}
template <class T, class U,
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), int> = 0>
bool operator==(Base<T> const &, U const &) {
std::cout << "operator==(Base, U)" << std::endl;
return true;
}
template <class U, class T,
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), int> = 0>
bool operator==(U const &, Base<T> const &) {
std::cout << "operator==(U, Base)" << std::endl;
return true;
}
int main() {
Base<int> b1, b2;
b1 == 42; // gcc and clang compile, msvc does not
}
MSVC 抛出编译错误 C2676: binary '==': 'Base<int>' does not define this operator or a conversion to a type acceptable to the predefined operator
。
clang 和 gcc 按预期调用 operator==(Base, U)
。
有趣的是,如果我删除 Base
中的所有成员并将其定义为 template <class T> struct Base{};
.
,结果是相同的
背景:我有另一个 class template <class T> Derived : Base<T>
不包含额外数据。我想重用所有 operator==
而不必为 Derived
重新定义它们。如果没有 SFINEA 的东西,将 Derived<int>
与 int
进行比较会导致模糊的运算符调用,因为底部的两个 operator==
定义将 U
推断为 Derived<int>
(AFAIK正确)。所以我的想法是禁用它们以强制编译器使用 operator==(Base<T> const &, Base<U> const &)
。但是后来我遇到了上面的问题。
此外,除了为 Base
和 Derived
的所有组合定义运算符之外,是否有解决方法?
我很惊讶 MSVC 没有编译您的代码,在我看来这完全正确。
所以...不确定...但我想这是一个 MSVC 错误。
无论如何...鉴于您还要求解决方法...我看到如果您 enable/disable 运算符的 return 类型,那么 MSVC 也适用于 SFINAE,所以我建议你重写你的运营商如下
template <class T, class U>
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), bool> operator==(Base<T> const &, U const &) {
std::cout << "operator==(Base, U)" << std::endl;
return true;
}
template <class U, class T>
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), bool> operator==(U const &, Base<T> const &) {
std::cout << "operator==(U, Base)" << std::endl;
return true;
}
下面是一个完整的编译示例,还有一个 Derived
class
#include <iostream>
#include <type_traits>
template <class T>
struct Base {
Base() = default;
Base(T) {}
static constexpr bool isBase = true;
};
struct Derived : public Base<int>
{ };
template <class U>
constexpr std::enable_if_t<U::isBase, bool> EnableComparisonWithValue(U const *) {
return false;
}
template <class>
constexpr bool EnableComparisonWithValue(...) {
return true;
}
template <class T, class U>
bool operator==(Base<T> const &, Base<U> const &) {
std::cout << "operator==(Base, Base)" << std::endl;
return true;
}
template <class T, class U>
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), bool> operator==(Base<T> const &, U const &) {
std::cout << "operator==(Base, U)" << std::endl;
return true;
}
template <class U, class T>
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), bool> operator==(U const &, Base<T> const &) {
std::cout << "operator==(U, Base)" << std::endl;
return true;
}
int main() {
Base<int> b1, b2;
Derived d1, d2;
b1 == b2; // Compiles fine
b1 == 42; // gcc and clang compile, msvc does not
d1 == d2;
d1 == b1;
b2 == d2;
d1 == 42;
42 == d2;
}
以下示例使用 gcc 和 clang 编译良好,但无法在 MSVC 中编译。我想知道我是否无意中跌入了非标准领域?如果不是,哪个编译器是正确的?是否有解决方法? 最小示例 (https://godbolt.org/z/PG35hPGMW):
#include <iostream>
#include <type_traits>
template <class T>
struct Base {
Base() = default;
Base(T) {}
static constexpr bool isBase = true;
};
template <class U>
constexpr std::enable_if_t<U::isBase, bool> EnableComparisonWithValue(U const *) {
return false;
}
template <class>
constexpr bool EnableComparisonWithValue(...) {
return true;
}
template <class T, class U>
bool operator==(Base<T> const &, Base<U> const &) {
std::cout << "operator==(Base, Base)" << std::endl;
return true;
}
template <class T, class U,
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), int> = 0>
bool operator==(Base<T> const &, U const &) {
std::cout << "operator==(Base, U)" << std::endl;
return true;
}
template <class U, class T,
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), int> = 0>
bool operator==(U const &, Base<T> const &) {
std::cout << "operator==(U, Base)" << std::endl;
return true;
}
int main() {
Base<int> b1, b2;
b1 == 42; // gcc and clang compile, msvc does not
}
MSVC 抛出编译错误 C2676: binary '==': 'Base<int>' does not define this operator or a conversion to a type acceptable to the predefined operator
。
clang 和 gcc 按预期调用 operator==(Base, U)
。
有趣的是,如果我删除 Base
中的所有成员并将其定义为 template <class T> struct Base{};
.
背景:我有另一个 class template <class T> Derived : Base<T>
不包含额外数据。我想重用所有 operator==
而不必为 Derived
重新定义它们。如果没有 SFINEA 的东西,将 Derived<int>
与 int
进行比较会导致模糊的运算符调用,因为底部的两个 operator==
定义将 U
推断为 Derived<int>
(AFAIK正确)。所以我的想法是禁用它们以强制编译器使用 operator==(Base<T> const &, Base<U> const &)
。但是后来我遇到了上面的问题。
此外,除了为 Base
和 Derived
的所有组合定义运算符之外,是否有解决方法?
我很惊讶 MSVC 没有编译您的代码,在我看来这完全正确。
所以...不确定...但我想这是一个 MSVC 错误。
无论如何...鉴于您还要求解决方法...我看到如果您 enable/disable 运算符的 return 类型,那么 MSVC 也适用于 SFINAE,所以我建议你重写你的运营商如下
template <class T, class U>
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), bool> operator==(Base<T> const &, U const &) {
std::cout << "operator==(Base, U)" << std::endl;
return true;
}
template <class U, class T>
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), bool> operator==(U const &, Base<T> const &) {
std::cout << "operator==(U, Base)" << std::endl;
return true;
}
下面是一个完整的编译示例,还有一个 Derived
class
#include <iostream>
#include <type_traits>
template <class T>
struct Base {
Base() = default;
Base(T) {}
static constexpr bool isBase = true;
};
struct Derived : public Base<int>
{ };
template <class U>
constexpr std::enable_if_t<U::isBase, bool> EnableComparisonWithValue(U const *) {
return false;
}
template <class>
constexpr bool EnableComparisonWithValue(...) {
return true;
}
template <class T, class U>
bool operator==(Base<T> const &, Base<U> const &) {
std::cout << "operator==(Base, Base)" << std::endl;
return true;
}
template <class T, class U>
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), bool> operator==(Base<T> const &, U const &) {
std::cout << "operator==(Base, U)" << std::endl;
return true;
}
template <class U, class T>
std::enable_if_t<EnableComparisonWithValue<U>(nullptr), bool> operator==(U const &, Base<T> const &) {
std::cout << "operator==(U, Base)" << std::endl;
return true;
}
int main() {
Base<int> b1, b2;
Derived d1, d2;
b1 == b2; // Compiles fine
b1 == 42; // gcc and clang compile, msvc does not
d1 == d2;
d1 == b1;
b2 == d2;
d1 == 42;
42 == d2;
}