c++ - C++20 概念需要运算符重载与用户定义的模板运算符重载函数相结合
问题描述
情况1
考虑以下concept
哪些a是可打印requires
的:value_type
range
R
#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::vector<int>
于不同的三个编译器:
static_assert(printable_range<std::vector<int>>);
但是如果我在定义之后定义operator<<
了任何类型的模板函数:x
concepts
std::ostream& operator<<(std::ostream& os, const auto& x) { return os << x; }
GCC 和 MSVC 可以通过以下断言但 Clang失败:
static_assert(printable_range<std::vector<std::vector<int>>>);
我应该信任哪个编译器?这似乎是一个 Clang 错误。
案例2
奇怪的是,如果我在定义之前定义了一个S
支持operator<<
的自定义结构concept
printable_range
:
struct S{};
std::ostream& operator<<(std::ostream& os, const S&) { return os; }
MSVC 的相同断言失败,但 GCC 仍然接受它:
static_assert(printable_range<std::vector<std::vector<int>>>);
它是一个 MSVC 错误吗?
案例3
如果我将operator<<
函数转换为命名函数print
,那么所有编译器都会在第二个断言上失败。这让我感到惊讶,因为它看起来等同于案例 1,这里的关键点是成员函数与自由函数或运算符重载函数与自由函数?
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!
解决方案
我应该信任哪个编译器?这似乎是一个 Clang 错误。
这是一个 GCC/MSVC 错误。Name lookup foros << x
将执行与参数相关的查找以查找任何其他关联operator<<
的 s,但这里关联的命名空间只是std
. 你不在,所以查找operator<<
不应该找到它,所以应该没有可行的候选人。namespace std
GCC 和 MSVC 这样做的事实是一个错误。
GCC 的问题在于它与操作员的查找,具体来说,只是找到了比它应该的更多的东西(参见51577,感谢 TC)。这就是为什么它可以找到operator<<
但不能找到print
.
实际上,这些是相同的示例,只是名称不同(print
vs operator<<
),它们应该具有相同的行为。
推荐阅读
- next.js - React-Leaflet 和自动快照/保存到 PNG
- python - Django中的URL解析有两种模式
- r - 显示多个变量和几何图形的时间序列的 ggplot 图例
- python - 删除 HTML 标签 python
- kubernetes - Kubernetes 中的高级用户是什么?
- c# - 如何从 C# 中的属性获取验证属性名称
- image - 如何使用 FFmpeg 从图像中创建全长视频?
- reporting-services - SSRS 在页眉中显示变量数据未在后续页面上显示
- f# - F# Interactive 与 nuget 参考:未定义命名空间
- ios - Xcode Simulator 测试并行化编号