为什么 std::forward_list::remove 和 std::erase<std::forward_list> 的值类型不同?

Why do std::forward_list::remove and std::erase<std::forward_list> have different types for value?

std::forward_list 有一个 member function:

size_type remove(const T& value);

和一个non-member function std::erase声明如下:

template<class T, class Alloc, class U>
typename forward_list<T, Alloc>::size_type
    erase(forward_list<T, Alloc>& c, const U& value);

请注意,非成员函数 std::erasevalue 的类型不同 U;而成员函数 remove 只使用 T 类型 value

为什么 std::erase 不直接为 value 使用类型 T

不一致背后有什么设计原理吗?

正如在 cppreference.com 上指出的那样:

Unlike std::forward_list::remove, erase accepts heterogenous types and does not force a conversion to the container's value type before invoking the == operator.

因此,对于 std::erase(),为 TU 定义 operator== 就足够了,而不会对 U 转换为 [ 施加限制=12=] 与 remove() 成员函数相比,它提供了更多的自由。

我可以看到一个实际的原因。它与模板参数推导带来的困难有关。想象一下这个假设函数:

template<typename T>
void foo(std::forward_list<T> const&, T const&) {}

这次调用你会得到什么?

std::forward_list<double> l;
foo(l, 1);

答案是您在模板参数推导中出错。根据一种说法,T 是双精度的,但根据另一种说法,它是整数。如果我要写 erase,我也会使用两个不同的模板参数,只是为了避免在无辜代码中出现此类问题。

现在remove不是成员模板,它是任何特化的常规成员函数。所以你可以毫无问题地写:

std::forward_list<double> l;
// later
l.remove(1);

1 是一个整数,它与 remove 期望的 double 不匹配。但是,这不是问题。因为remove是具体特化的常规成员函数,隐式转换是可能的。