bob*_*eff 4 c++ templates stl sfinae c++17
我有两个erase_all_if
函数模板的实现。
template <typename Container, typename Pred>
typename Container::size_type erase_all_if(Container& c, Pred&& pred)
{
auto newend = std::remove_if(c.begin(), c.end(), std::forward<Pred>(pred));
auto ret = c.end() - newend;
c.erase(newend, c.end());
return ret;
}
template <typename Container, typename Pred>
auto erase_all_if(Container& c, Pred&& pred) {
typename Container::size_type removed = 0;
for (auto it = c.begin(); it != c.end();) {
if (pred(*it)) {
it = c.erase(it);
++removed;
}
else {
++it;
}
}
return removed;
}
Run Code Online (Sandbox Code Playgroud)
第一个仅适用于容器,std::vector
因为它需要随机访问迭代器,第二个适用于所有容器,但它对于连续容器效率较低,并且适用于基于节点的容器。如何消除两个版本的歧义?我当前使用的 C++ 标准是 C++17。
这里不需要 SFINAE。您可以在此处添加辅助模板,该模板接收交互器类别作为附加参数。您甚至可以通过一些调整来使用 C++11 来实现此功能。
// helper templates with overloads taking a parameter indicating info about the iterator category
namespace impl
{
template<class T>
constexpr typename std::iterator_traits<decltype(std::declval<T>().begin())>::iterator_category ContainerIteratorCategory_v {};
template <typename Container, typename Pred>
typename Container::size_type erase_all_if(std::random_access_iterator_tag, Container& c, Pred&& pred)
{
auto newend = std::remove_if(c.begin(), c.end(), std::forward<Pred>(pred));
auto ret = c.end() - newend;
c.erase(newend, c.end());
return ret;
}
template <typename Container, typename Pred>
auto erase_all_if(std::input_iterator_tag, Container& c, Pred&& pred) {
typename Container::size_type removed = 0;
for (auto it = c.begin(); it != c.end();) {
if (pred(*it)) {
it = c.erase(it);
++removed;
}
else {
++it;
}
}
return removed;
}
}
template <typename Container, typename Pred>
auto erase_all_if(Container& c, Pred&& pred) {
return impl::erase_all_if(impl::ContainerIteratorCategory_v<Container>, c, std::forward<Pred>(pred));
}
template<class Container>
void Print(Container const& c)
{
for (auto& e : c)
{
std::cout << e << '\n';
}
}
int main()
{
{
std::vector<int> v{ 1, 2, 3, 4, 5 };
std::cout << "std::vector<int>: " << erase_all_if(v, [](int i) { return (i % 2) == 0; }) << '\n';
Print(v);
}
{
std::list<int> l{6, 7, 8, 9, 10};
std::cout << "std::list<int>: " << erase_all_if(l, [](int i) { return (i % 2) == 0; }) << '\n';
Print(l);
}
}
Run Code Online (Sandbox Code Playgroud)
这里你不需要 SFINAE。我会将这两个功能合并为一个,然后执行
if constexpr (std::is_base_of_v<std::random_access_iterator_tag,
typename std::iterator_traits<decltype(c.begin())>::iterator_category>)
{
// ...
}
else
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
或者您可以使用标签调度:(请注意,迭代器类别相互继承,因此这可以很好地处理类别之间的回退)
template <typename Container, typename Pred>
typename Container::size_type erase_all_if_low(std::random_access_iterator_tag, Container& c, Pred&& pred)
{
// ...
}
template <typename Container, typename Pred>
typename Container::size_type erase_all_if_low(std::forward_iterator_tag, Container& c, Pred&& pred)
{
// ...
}
template <typename Container, typename Pred>
auto erase_all_if(Container& c, Pred &&pred)
{
using category = typename std::iterator_traits<decltype(c.begin())>::iterator_category;
return erase_all_if_low(category{}, c, std::forward<Pred>(pred));
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
74 次 |
最近记录: |