SFINAE 代码检测是否为一个类型实现了 operator<< 在 Clang 和 gcc 上表现不同
SFINAE code to detect whether operator<< is implemented for a type behaves differently on Clang and gcc
我只是在玩弄一些 SFINAE 代码,但我无法让它工作。我正在使用 Xcode 12.2 和 -std=c++17。
godbolt 揭示了 Clang 无论如何确实选择了 false_type 变体,而 gcc 使用 true_type 变体,如果两个模板参数相同并且实现了运算符,正如我所期望的那样。请看下面的代码:
#include <iostream>
#include <type_traits>
struct MyStruct {};
std::ostream& operator<<(std::ostream& os, const MyStruct&) {
return os;
}
template<typename T, typename U = void>
struct has_ostream_operator : std::false_type {};
template<typename T>
struct has_ostream_operator<T, typename std::enable_if_t<sizeof(std::declval<std::ostream&>() << std::declval<T>()), T>> : std::true_type {};
int main() {
constexpr bool res = has_ostream_operator<MyStruct, MyStruct>::value;
if constexpr(res) {
std::cout << "Yes";
} else {
std::cout << "No";
}
return 0;
}
有人可以向我解释这里发生了什么以及为什么 Clang 和 gcc 会表现不同吗?我已经使用不同的技术解决了这个问题,所以这仅用于教育目的:-)
如果您将整个 sizeof
结构替换为 42
,两个编译器都会给您一个错误,说明 sizeof
不是 bool
并且不能缩小到一.
换成1
就没有错误了(因为1显然可以缩小到true
)。
考虑到这一点,让我们明确地传递一个 bool
:
template<typename T>
struct has_ostream_operator<
T,
typename std::enable_if_t<
sizeof(std::declval<std::ostream&>() << std::declval<T>()) != 0,
// ^^^^^
T
>
> : std::true_type {};
现在可以了。
两种实现都为 sizeof(std::declval<std::ostream&>() << std::declval<MyStruct>())
提供了 272
,所以它们只是在 SFINAEness 期间以不同方式处理此错误。我认为是 GCC bug 57891.
我只是在玩弄一些 SFINAE 代码,但我无法让它工作。我正在使用 Xcode 12.2 和 -std=c++17。 godbolt 揭示了 Clang 无论如何确实选择了 false_type 变体,而 gcc 使用 true_type 变体,如果两个模板参数相同并且实现了运算符,正如我所期望的那样。请看下面的代码:
#include <iostream>
#include <type_traits>
struct MyStruct {};
std::ostream& operator<<(std::ostream& os, const MyStruct&) {
return os;
}
template<typename T, typename U = void>
struct has_ostream_operator : std::false_type {};
template<typename T>
struct has_ostream_operator<T, typename std::enable_if_t<sizeof(std::declval<std::ostream&>() << std::declval<T>()), T>> : std::true_type {};
int main() {
constexpr bool res = has_ostream_operator<MyStruct, MyStruct>::value;
if constexpr(res) {
std::cout << "Yes";
} else {
std::cout << "No";
}
return 0;
}
有人可以向我解释这里发生了什么以及为什么 Clang 和 gcc 会表现不同吗?我已经使用不同的技术解决了这个问题,所以这仅用于教育目的:-)
如果您将整个 sizeof
结构替换为 42
,两个编译器都会给您一个错误,说明 sizeof
不是 bool
并且不能缩小到一.
换成1
就没有错误了(因为1显然可以缩小到true
)。
考虑到这一点,让我们明确地传递一个 bool
:
template<typename T>
struct has_ostream_operator<
T,
typename std::enable_if_t<
sizeof(std::declval<std::ostream&>() << std::declval<T>()) != 0,
// ^^^^^
T
>
> : std::true_type {};
现在可以了。
两种实现都为 sizeof(std::declval<std::ostream&>() << std::declval<MyStruct>())
提供了 272
,所以它们只是在 SFINAEness 期间以不同方式处理此错误。我认为是 GCC bug 57891.