考虑以下概念
,其中需要
范围
R
的value_type
是可打印的:
#include <iostream>
#include <iterator>
template <class R, typename T = std::ranges::range_value_t<R>>
concept printable_range = requires(std::ostream& os, const T& x) { os << x; };
它可以很好地与std::向量
static_assert(printable_range<std::vector<int>>);
但是如果我定义一个模板运算符
std::ostream& operator<<(std::ostream& os, const auto& x) { return os << x; }
GCC和MSVC可以传递以下断言,但Clang失败:
static_assert(printable_range<std::vector<std::vector<int>>>);
我应该信任哪个编译器?它看起来像一个Clangbug。
奇怪的是,如果我用运算符定义一个自定义struct
S
struct S{};
std::ostream& operator<<(std::ostream& os, const S&) { return os; }
同样的断言在MSVC中失败,但GCC仍然接受它:
static_assert(printable_range<std::vector<std::vector<int>>>);
是MSVCbug吗?
如果我转换运算符
void print(int x) { std::cout << x; };
template <class R, typename T = std::ranges::range_value_t<R>>
concept printable_range = requires(const T& x) { print(x); };
void print(auto x) { std::cout << x; };
static_assert(printable_range<std::vector<int>>);
static_assert(printable_range<std::vector<std::vector<int>>>); // failed!
我应该信任哪个编译器?它看起来像一个Clangbug。
这是一个GCC/MSVCbug。os的名称查找
GCC和MSVC这样做的事实是bug。
GCC的问题是,它使用运算符进行查找,具体来说,只是找到了比它应该找到的更多的东西(参见51577,感谢T. C.)。这就是为什么它可以找到运算符
真的,这些是同一个示例,只是名称不同(print
vs运算符
Clang是正确的。这是通常的两阶段查找规则,已知GCC对运算符的处理不正确(MSVC也不完全以正确的两阶段查找支持而闻名,尽管它们正在变得更好)。
运算符的普通不合格查找