使用模板化分配器和对对向量对进行排序的函数

Function that sorts a vector of pairs with templated allocator and pairs

这是我的函数,它按对的第一个元素对对的向量进行排序。

std::vector<std::pair<int,std::string>>
sort_pairs(std::vector<std::pair<int,std::string>>&& items)
{
    std::sort(std::begin(items),std::end(items));
    return items;
}

但是当我尝试将其概括为接受任何类型的分配器和任何类型的分配器时,我得到了一堆错误(太多无法粘贴到这里)。我使用右值引用作为参数,因为该函数是在其他函数内部调用的,复制参数也可以,但我认为它的效率会降低。这是我尝试过的一些方法。

template <typename Allocator,
          typename P1 = typename Allocator::value_type::first_type,
          typename P2 = typename Allocator::value_type::second_type>
Allocator<std::pair<P1,P2>> sort_pairs(Allocator<std::pair<P1,P2>>&& items)
{
    std::sort(std::begin(items),std::end(items));
    return items;
}

如果您在代码中添加一些 c++20 提示,我将不胜感激。点赞要求

您应该使用“template template parameter”来表达您的 Allocator

如下

template <template <typename...> class Allocator,
          typename P1, typename P2>
Allocator<std::pair<P1, P2>>
   sort_pairs (Allocator<std::pair<P1, P2>> && items)
 {
   std::sort(std::begin(items),std::end(items));
   return items;
 }

从 C++17 开始你可以使用 typename 而不是 class 来定义它

// ..............................VVVVVVVV                                     
template <template <typename...> typename Allocator,

class 仍然有效,恕我直言,更可取。

观察到 Allocator 拦截 std::vector(模板 class,而不是 std::vector<std::pair<int, std::string>> 的特定专业化)所以你不能提取 P1P2 从它作为你的例子

// ....................VVVVVVVVV  not usable this way                       
typename P1 = typename Allocator::value_type::first_type

你应该写

typename Allocator<std::pair<P1, P2>>::value_type::first_type

但是,很明显,您不能使用它为 P1 提供默认类型,因为您必须知道 P1.

幸运的是,P1P2 可以从 items 参数推导出来,因此您不需要默认类型。

底层类型是显着对这一事实吗?算法的主体不以任何方式使用它。我们可以从以下开始:

template <typename R>
std::decay_t<R> sort(R&& items)
{
    std::sort(std::begin(items),std::end(items));
    return items;
}

在 C++20 中,我们可以通过要求 R 是一个其迭代器可排序的范围来适当地限制 - 是的,有一个概念:

template <std::ranges::range R>
    requires std::sortable<std::ranges::iterator_t<R>>
std::decay_t<R> sort(R&& items)
{
    std::sort(std::ranges::begin(items), std::ranges::end(items));
    return items;
}

如果你真的想要求这是一个范围内的对,你可以将其添加为一个单独的约束:

template <std::ranges::range R>
    requires std::sortable<std::ranges::iterator_t<R>> &&
             is_specialization_of<std::ranges::range_value_t<R>, std::pair>
std::decay_t<R> sort(R&& items)
{
    std::sort(std::ranges::begin(items), std::ranges::end(items));
    return items;
}

我将 is_specialization_of 的实施留作练习。