First, you want to write a simple operator<< overload to print your std::vectors
First iteration:
Now, let us look at a sample main() which uses this
What if we want to change our operator overload to be only used if the passed type is indeed that can be printed? E.g., line 9 of the main should have some readable error message in it.
Second Iteration:
with this update to our code, now the failure on main()'s line 9 has a better error message:
g++10:
concept.cpp:27:14: note: constraints not satisfied
clang++12:
concept.cpp:27:14: note: candidate template ignored: constraints not satisfied [with T = std::pair<int, int>] ostream& operator<< (ostream& os, const vector<T>& v) { ^concept.cpp:26:12: note: because 'std::pair<int, int>' does not satisfy 'printable' template <printable T> ^concept.cpp:9:7: note: because 'cout << t' would be invalid: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'std::pair<int, int>') cout << t;However, this is where it gets interesting!
clang++12 fails for
as well; with a similar error.
concept.cpp:27:14: note: candidate template ignored: constraints not satisfied [with T = std::vector<int>] ostream& operator<< (ostream& os, const vector<T>& v) { ^concept.cpp:26:12: note: because 'std::vector<int>' does not satisfy 'printable' template <printable T> ^concept.cpp:9:7: note: because 'cout << t' would be invalid: call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup cout << t;Need to inspect how g++ and Clang++ actually implement concepts behding the scene - looks like g++ uses a recursive-kinda check for the satisfiability.
to be continued...