我看过这个使用SFINAE来检查一个类型是否是可流的here的例子。但是,我注意到它是不可移植的,也就是说,对于不同的编译器,模板化的类型返回不同的结果。我很乐意提供任何提示来理解这里的问题。
下面的代码对于任何版本的clang++和GCC 12或更高版本都返回true, false
,但对于早期版本的GCC则返回true, true
。
您可以在线试用here。
#include <iostream>
#include <type_traits>
#include <vector>
template <typename T, typename dummy = void>
struct is_printable : std::false_type {};
template <typename T>
struct is_printable<
T, typename std::enable_if_t<std::is_same_v<
std::remove_reference_t<decltype(std::cout << std::declval<T>())>,
std::ostream>>> : std::true_type {};
template <typename T>
inline constexpr bool is_printable_v = is_printable<T>::value;
struct C {};
std::ostream& operator<<(std::ostream& os, const C& c) {
os << "C";
return os;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
for (const auto& el : v) {
os << el;
}
return os;
}
int main(int argc, const char* argv[]) {
std::cout << std::boolalpha;
std::cout << is_printable_v<C> << std::endl;
std::cout << is_printable_v<std::vector<int>> << std::endl;
return 0;
}
2条答案
按热度按时间5ssjco0h1#
operator<<(std::ostream& os, const std::vector<T>& v)
不会被ADL找到(对于std::vector<int>
,它会被std::vector<C>
找到)(因此需要在使用前声明才能使用)。这就是为什么正确答案是
true
,false
。以前版本的gcc在这方面表现不佳。注意:不鼓励为您不拥有的类型重载运算符。std可能在将来添加该重载,并且您将违反ODR(一个定义规则)。如果另一个库做了与您相同的错误事情,也是如此。
x8diyxa72#
添加转发声明帮助:
完整代码:
演示:https://godbolt.org/z/qKz537TPr
我知道我没有回答“为什么两个版本的行为不同”,但我认为这可能会有帮助:)