为什么 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::erase
与 value
的类型不同 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()
,为 T
和 U
定义 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
是具体特化的常规成员函数,隐式转换是可能的。
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::erase
与 value
的类型不同 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()
,为 T
和 U
定义 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
是具体特化的常规成员函数,隐式转换是可能的。