case 1
Consider the following concept which requires the value_type of a range R is printable:
#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; };
It works fine with std::vector<int> on different three compliers:
static_assert(printable_range<std::vector<int>>);
but if I define a template operator<< function with any type x after concepts define:
std::ostream& operator<<(std::ostream& os, const auto& x) { return os << x; }
GCC and MSVC can pass the following assert but Clang fails:
static_assert(printable_range<std::vector<std::vector<int>>>);
Which compiler should I trust? It seems like a Clang bug.
case 2
Weirdly, If I define a custom struct S with operator<< support before the concept printable_range define:
struct S{};
std::ostream& operator<<(std::ostream& os, const S&) { return os; }
Same assert fails with MSVC, but GCC still accept it:
static_assert(printable_range<std::vector<std::vector<int>>>);
Is it an MSVC bug?
case3
If I transform the operator<< function into a named function print, then all the compiler fails on the second assert. This surprised me since it looks equivalent to case 1, the key points here are the member function vs. free function or operator overloading function vs. free function?
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!