std::forward_list
has a member function:
size_type remove(const T& value);
and a non-member function std::erase
declared as follows:
template<class T, class Alloc, class U>
typename forward_list<T, Alloc>::size_type
erase(forward_list<T, Alloc>& c, const U& value);
Please note that non-member function std::erase
has a different type U
for value
; while member function remove
just use type T
for value
.
Why doesn't std::erase
just use type T
for value
?
Is there any design rationale behind the inconsistent?
I can see a practical reason. And it has to do with the difficulties imposed by template argument deduction. Imagine this hypothetical function:
template<typename T>
void foo(std::forward_list<T> const&, T const&) {}
What do you get for this invocation?
std::forward_list<double> l;
foo(l, 1);
The answer is that you get an error in template argument deduction. According to one argument T
is double, but according to the other it's int. If I was to write erase
, I'd use two different template arguments as well, if only to avoid such issues in innocent code.
Now remove
is not a member template, it is a regular member function of any specialization. So you can write, without problem:
std::forward_list<double> l;
// later
l.remove(1);
1
is an integer, it doesn't match the double
that remove
expects. However, that is not a problem. Because remove
is a regular member function of a concrete specialization, and an implicit conversion is possible.