以下示例使用 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 和 gccoperator==(Base, U)按預期呼叫。有趣的是,如果我洗掉所有成員Base并將其定義為template <class T> struct Base{};.
Background: I have another class template <class T> Derived : Base<T> which does not contain additional data. I would like to reuse all the operator== without having to redefine them again for Derived. Without the SFINEA stuff, comparing a Derived<int> with an int results in an ambiguous operator call, because the bottom two operator== definitions deduce U as Derived<int> (AFAIK correctly). So my idea was do disable them to force the compiler to use operator==(Base<T> const &, Base<U> const &). But then I came upon the above problem.
Also, is there maybe a workaround apart from defining the operators for all combinations of Base and Derived?
uj5u.com熱心網友回復:
我很驚訝 MSVC 沒有編譯你的代碼,這在我看來是完全正確的。
所以......不確定......但我想這是一個 MSVC 錯誤。
無論如何...鑒于您還要求解決方法...我看到如果您啟用/禁用運算子的回傳型別,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類
#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;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/447268.html
標籤:c templates c 17 operator-overloading sfinae
