Arm*_*mut 7 c++ gcc clang sfinae language-lawyer
我在这里看到了使用 SFINAE 检查类型是否可流式传输的示例。但是,我注意到它不可移植,即使用不同的编译器为模板化类型返回不同的结果。我很高兴能提供任何帮助理解这里问题的提示。
下面的代码返回true, false
任何版本的 clang++ 和 GCC 12 或更高版本,但true, true
使用早期版本的 GCC。
您可以在这里在线尝试。
#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;
}
Run Code Online (Sandbox Code Playgroud)
operator<<(std::ostream& os, const std::vector<T>& v)
ADL 不会找到(对于std::vector<int>
,它会被发现std::vector<C>
)(因此需要在使用之前声明才能使用)。
这就是为什么正确答案是true
,false
。以前版本的 gcc 在这方面行为不当。
注意:不鼓励为您不拥有的类型重载运算符。std 将来可能会添加该重载,并且您将违反 ODR(一个定义规则)。如果另一个图书馆做了与你同样的错误事情,情况也是如此。