简体   繁体   English

使用std :: iterator traits和auto在函数声明中定义一个函数

[英]Define a function in function declaration using std::iterator traits and auto

Today I tried to implement radix sort. 今天我尝试实现基数排序。 The function must have two variables: begin iterator and end iterator, and can have third: some function that must return the integer type to sort by. 该函数必须有两个变量:begin iterator和end iterator,并且可以有第三个:一些函数必须返回整数类型才能排序。 By default it must be the identity function. 默认情况下,它必须是身份功能。

My tries look like (sorry, code looks very long and dirty, but it's just a try): 我的尝试看起来像(对不起,代码看起来很长很脏,但它只是一个尝试):

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; }) {
        // ...
}

The returning type of get_value, of course, will be known in compilation time . 当然,返回类型的get_value将在编译时知道

Usage should be: 用法应该是:

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; })

Or: 要么:

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

It doesn't even compile and I don't know how to solve the problem. 它甚至没有编译,我不知道如何解决问题。 How to do it? 怎么做? Simple example: 简单的例子:

#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());
}

Compiler output: 编译器输出:

source_file.cpp:17:37: error: no matching function for call to ‘radix_sort(std::vector<unsigned int>::iterator, std::vector<unsigned int>::iterator)’
     radix_sort(vec.begin(), vec.end());
                                      ^
source_file.cpp:6:6: note: candidate: template<class ForwardIt, class auto:1> void radix_sort(ForwardIt, ForwardIt, std::function<auto:1(typename std::iterator_traits<_Iter>::value_type)>)
 void radix_sort(
      ^
source_file.cpp:6:6: note:   template argument deduction/substitution failed:
source_file.cpp:17:37: note:   couldn't deduce template parameter ‘auto:1’
     radix_sort(vec.begin(), vec.end());

The easy way to fix this is to not have a default function and instead have two overloads. 解决这个问题的简单方法是没有默认函数,而是有两个重载。 This lets you get rid of using a std::function , which is expensive, at the cost of writing a couple lines of boiler plate code. 这可以让你摆脱使用std::function ,这是昂贵的,代价是编写几行样板代码。 If you use 如果你使用

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; });
}

the you get the default "identity" with no function, and you get the exact function object otherwise if one is provided. 你得到没有功能的默认“身份”,你得到了确切的功能对象,否则提供了一个。

For the benefit of future users, I would like to point out that C++20 introduces the class std::identity , which aids in solving the problem. 为了未来用户的利益,我想指出C ++ 20引入了类std::identity ,它有助于解决问题。 With its help, the code can be rewritten as: 在它的帮助下,代码可以重写为:

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

And it is very easy to implement a standard-conforming one yourself if you don't have C++20, like this: 如果你没有C ++ 20,很容易自己实现一个符合标准的,如下所示:

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

  using is_transparent = void;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM