使用std :: iterator特征和auto在函数声明中定义函数

时间:2019-05-13 12:38:21

标签: c++ c++11

今天,我尝试实现基数排序。该函数必须具有两个变量:Begin Iterator和End Iterator,并且可以具有第三个变量:一些必须返回整数类型进行排序的函数。默认情况下,它必须是身份功能。

我的尝试看起来像(抱歉,代码看起来很长很脏,但这只是尝试):

.call()

当然,在编译时就会知道get_value的返回类型。

用法应为:

template<class ForwardIt>
void radix_sort(
    ForwardIt first,
    ForwardIt last,
    std::function<auto(typename std::iterator_traits<ForwardIt>::value_type)> get_value =
    [](const typename std::iterator_traits<ForwardIt>::value_type& x){ return x; }) {
        // ...
}

或者:

std::vector<std::pair<uint32_t, std::string>> vec;
// ...
radix_sort(vec.begin(), vec.end(), [](const std::pair<uint32_t, std::string>& x){ return x.first; })

它甚至没有编译,我也不知道如何解决问题。怎么做?简单的例子:

std::vector<uint32_t> vec;
// ...
radix_sort(vec.begin(), vec.end());

编译器输出:

#include <bits/stdc++.h>

template<class ForwardIt>
void radix_sort(
    ForwardIt first,
    ForwardIt last,
    std::function<auto(typename std::iterator_traits<ForwardIt>::value_type)> get_value =
    [](const typename std::iterator_traits<ForwardIt>::value_type& x){ return x; }) {
        // ...
}

int main()
{
    std::vector<std::pair<uint32_t, std::string>> vec(10);
    radix_sort(vec.begin(), vec.end());
}

2 个答案:

答案 0 :(得分:8)

解决此问题的简单方法是不具有默认功能,而是具有两个重载。这样一来,您就不必使用昂贵的std::function了,只需编写几行样板代码即可。如果您使用

template<class ForwardIt, class Func>
void radix_sort(ForwardIt first, ForwardIt last, Func get_value) {
    // ...
}

template<class ForwardIt>
void radix_sort(ForwardIt first, ForwardIt last) {
    radix_sort(first, last, [](const typename std::iterator_traits<ForwardIt>::value_type& x){ return x; });
}

您将获得没有功能的默认“身份”,否则将获得确切的功能对象(如果提供了该对象)。

答案 1 :(得分:6)

为了将来的用户的利益, 我想指出的是C ++ 20引入了类std::identity, 这有助于解决问题。 有了它的帮助 该代码可以重写为:

template <typename For, typename F = std::identity>
void radix_sort(For first, For end, F f = {})
{
  /* ... */
}

您自己实施符合标准的程序非常容易 如果您没有C ++ 20,例如:

struct identity {
  template <class T>
  constexpr T&& operator()(T&& t) const noexcept
  {
    return std::forward<T>(t);
  }

  using is_transparent = void;
};