【发布时间】:2022-08-24 01:28:46
【问题描述】:
我正在尝试更多地了解概念。我在概念和受约束的模板函数之间遇到了一些循环依赖问题,我在一个简单的示例中重现了这些错误。
我有一个概念,Printable,当且仅当operator<< 是在一个类型上定义时,我才希望得到满足。我在可打印类型的向量上也有operator<< 的重载。
令我惊讶的是,std::vector<int> 不被视为 Printable,即使 operator<< 可以在上面工作。
#include <iostream>
#include <vector>
template <class T>
concept Printable = requires(std::ostream& out, T a) {
out << a;
};
template <Printable T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& vec) {
out << \'[\';
for (std::size_t i {}; i < vec.size(); i++) {
out << vec[i];
if (i < vec.size() - 1) {
out << \", \";
}
}
return out << \']\';
}
static_assert(Printable<int>); // This works as expected.
static_assert(Printable<std::vector<int>>); // This fails.
int main() {
std::vector<int> vec {1, 2, 3, 4};
std::cout << vec << \'\\n\'; // This works as expected.
}
这在 Clang++ 14.0.6_1 上失败,并显示以下消息:
stack_overflow/problem.cpp:26:1: error: static_assert failed
static_assert(Printable<std::vector<int>>); // This fails.
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
stack_overflow/problem.cpp:26:15: note: because \'std::vector<int>\' does not satisfy \'Printable\'
static_assert(Printable<std::vector<int>>); // This fails.
^
stack_overflow/problem.cpp:7:9: note: because \'out << a\' would be invalid: call to function \'operator<<\' that is neither visible in the template definition nor found by argument-dependent lookup
out << a;
^
1 error generated.
所以我的问题是:如果T 是Printable,我该怎么做才能使std::vector<T> 被视为Printable?
笔记:
-
我相信这与 g++ 一样编译得很好,但我最近搞砸了我的 GCC 设置,所以我目前无法确认这一点。如果这是真的,我很想知道为什么它适用于 g++ 而不是 clang++。
- 更新:Barry 的评论提醒我存在编译器资源管理器。我现在可以确认上面的代码可以在 g++ 上编译,但不能在 clang++ 上编译。我仍然很好奇为什么存在这种差异。
-
我相信我需要将运算符重载放在
Printable的声明之上。如果我这样做并删除约束,代码编译得很好。但是,如果可能,我想保留 Printable 约束,因为我相信保留这样的约束将在将来简化错误消息。
-
我怀疑你正在与 ADL 发生冲突。
-
@wojand:是的,在注释掉 static_asserts 的情况下,
std::cout << vec << \'\\n\'确实找到并使用了我的实现。它打印[1, 2, 3, 4]。 (等等,他们去哪儿了?我发誓我看到他们问这个...)
标签: c++ c++20 c++-concepts