I'm trying to understand what problems C++20 concepts are solving and how exactly they are helpful to the end user. I understand that it helps the compiler in resolving function calls, but from my cursory reading of it, from an end user standpoint, it doesn't seem to add much.
Consider this code:
void addToCollection(auto& collection, const auto& val) {
collection.push_back(val);
}
int main() {
vector<int> fooVec;
addToCollection(fooVec, 15);
unordered_set<int> fooSet;
addToCollection(fooSet, 15);
return 0;
}
The compiler issues a very obvious message telling us the function addToCollection
is not compatible with unordered_set
.
error: no member named 'push_back' in 'std::unordered_set<int>'
collection.push_back(val);
~~~~~~~~~~ ^
concept.cpp:34:5: note: in instantiation of function template specialization 'addToCollection<std::unordered_set<int>, int>'
requested here
addToCollection(fooSet, 15);
Prior to concepts, you'd resolve a failure like this by providing an explicit template specialization.
template<>
void addToCollection(unordered_set<int>& collection, const auto& val) {
collection.insert(val);
}
With concepts, it appears that the correct way to fix this is by placing a constraint on the function parameter type.
template<typename CollectionType>
concept HasPushBack = requires(CollectionType collection, typename CollectionType::value_type val) {
collection.push_back(val);
};
void addToCollection(HasPushBack auto& collection, const auto& val) {
collection.push_back(val);
}
void addToCollection(auto& collection, const auto& val) {
collection.insert(val);
}
As an end user I don't see what advantages I get from concepts in this example—why should I go through the exercise of defining a type constraint when in fact, I could provide an explicit template specialization and be done?