I am trying to learn more about concepts. I ran into some problems with circular dependencies between concepts and constrained template functions, and I've reproduced these errors in a simple example.
I have a concept, Printable, that I want to be satisfied if and only if operator<< is defined on a type. I also have an overload of operator<< on vectors of printable types.
To my surprise, std::vector<int> is not considered Printable, even though operator<< works on it.
#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.
}
This fails on Clang++ 14.0.6_1 with the following message:
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.
So my question is: what can I do to make std::vector<T> considered Printable if T is Printable?
Notes:
I believe this compiles fine as is with g++, but I recently screwed up my setup for GCC so I cannot confirm this at the moment. If this is true, I would love to know why it works for g++ but not clang++.
- Update: Barry's comment reminded me that Compiler Explorer exists. I can now confirm that the above code compiles on g++ but not on clang++. I still am curious about why this difference exists.
I believe I need to put the operator overload above the declaration of
Printable. If I do this and remove the constraint, the code compiles fine. However, I want to keep the Printable constraint if possible, as I believe keeping constraints like this will simplify error messages in the future.