I'm trying to implement something like Haskell Prelude in C++ with typeclasses like Functor, Monoid, and so on. So I've decided to use C++ Concepts to do the type checking, but I encountered a problem while trying to implement Semigroup concept.
The problem occurs when I try to declare a concept that uses some function that is declared and overloaded for needed types later in the code, but it's only relevant for some types like std::vector, but for my own types works well.
Full code:
template<class T>
struct S {
// ...
};
template<class T>
concept Addable = requires(T a, T b) {
{ add(a, b) } -> T;
};
template<class T>
S<T> add(const S<T> & a, const S<T> & b) {
// ...
return {};
}
template<class T>
std::vector<T> add(const std::vector<T> & a, const std::vector<T> & b) {
// ...
return {};
}
int main() {
std::cout << Addable<S<int>> << '\n';
std::cout << Addable<std::vector<int>> << '\n';
}
I expect the output 1 1, but the actual output is 1 0.
So, it doesn't recognize std::vector as Addable regardless to a declared add(std::vector) overload, but it does recognize the S type as Addable.
UPD:
The problem disappears if I move the add function to go before the Addable concept. But it looks very unhandy and unclear that I have to implement all concepts that I include for types like std::vector before I include those concepts.
UPD2: I use GCC 9.1.0.