C++ 将STL算法传递给另一个函数

C++ 将STL算法传递给另一个函数,c++,c++11,stl,C++,C++11,Stl,我有一个用户定义类型的向量(Student)。我有两个几乎相同的函数,除了其中的一个函数调用 以下是两个功能: Student lowest_grade(const std::vector<Student> &all_students){ return *std::min_element(std::begin(all_students), std::end(all_students), [](const Student &a, const Studen

我有一个用户定义类型的向量(Student)。我有两个几乎相同的函数,除了其中的一个函数调用

以下是两个功能:

Student lowest_grade(const std::vector<Student> &all_students){
  return *std::min_element(std::begin(all_students), std::end(all_students),
      [](const Student &a, const Student &b){
    return a.get_average() < b.get_average();});
}

Student highest_grade(const std::vector<Student> &all_students){
  return *std::max_element(std::begin(all_students), std::end(all_students),
      [](const Student &a, const Student &b){
    return a.get_average() < b.get_average();});
}
学生最低分数(const std::vector&所有学生){
return*std::min_元素(std::begin(所有学生),std::end(所有学生),
[](康斯特学生与a、康斯特学生与b){
返回a.get_average()
这两个函数在我的使用中都正常工作,但似乎可以很容易地构造出更好的函数。我想创建一个函数,可以传入minu元素或max元素,比如:

template <typename func>
Student dispatch(const std::vector<Student> &all_students, func){
  return *func(std::begin(all_students), std::end(all_students),
      [](const Student &a, const Student &b){
    return a.get_average() < b.get_average();});
}
模板
学生派遣(const std::vector&all_学生,func){
return*func(标准::开始(所有学生),标准::结束(所有学生),
[](康斯特学生与a、康斯特学生与b){
返回a.get_average()
但我无法让它正常工作。我不知道该怎么做

编辑-这是我调用分派函数+错误消息的方式:

std::cout<<"lowest: "<< dispatch(all_students, std::max_element);
std::cout这样就可以了:

template <typename func>
Student dispatch(const std::vector<Student> &all_students, const func& fn){
  return *fn(std::begin(all_students), std::end(all_students),
      [](const Student &a, const Student &b){
    return a.get_average() < b.get_average();});
}
模板
学生派遣(const std::vector&all_学生,const func&fn){
返回*fn(标准::开始(所有学生),标准::结束(所有学生),
[](康斯特学生与a、康斯特学生与b){
返回a.get_average()
模板参数只是某种类型的东西

我建议要小心,永远不要使用空向量调用此方法,因为它在取消引用空迭代器时会引发异常。最好是:

template <typename func>
Student dispatch(const std::vector<Student> &all_students, const func& fn){
  auto it = fn(std::begin(all_students), std::end(all_students),
      [](const Student &a, const Student &b){
    return a.get_average() < b.get_average();});
  if (it != all_students.end()) {
    return *it;
  }
  // Some exception handling, because returning an instance of student is not possible.
}
模板
学生派遣(const std::vector&all_学生,const func&fn){
自动it=fn(标准::开始(所有学生),标准::结束(所有学生),
[](康斯特学生与a、康斯特学生与b){
返回a.get_average()
另一个建议是在使用数据之前对学生进行分类。然后,您还可以获得其他统计数据,如中位数

std::sort(all_students.begin(), all_students.end() [](const Student &a, const Student &b){return a.get_average() < b.get_average();});
std::sort(all_Student.begin(),all_Student.end()[](const Student&a,const Student&b){返回a.get_average()
最低的学生是第一要素,最高的学生是最后一要素。这也将防止您引发异常

你的电话还有一个问题。您需要呼叫dispatch,如:

dispatch(all_students, std::max_element<std::vector<Student>::const_iterator, std::function<bool(const Student &, const Student &)>>);
dispatch(所有学生,标准::最大元素);

STL没有演绎魔法,无法自行决定您想要的
max\u元素
功能。因此您必须指定它。

std::max_元素
是一个模板函数,编译器无法以这种方式推断所需的模板类型

您可以使用以下命令强制选择所需的原型:

// Your lambda as functor
struct CompAverage
{
    bool operator () (const Student & a, const Student & b) const
    {
        return a.get_average() < b.get_average();
    }
};

using Student_IT = std::vector<Student>::const_iterator;

Student dispatch(const std::vector<Student> &all_students,
                 Student_IT (*f)(Student_IT, Student_IT, CompAverage))
{
    return *f(std::begin(all_students), std::end(all_students), CompAverage{});
}

int main()
{
    std::vector<Student> v(42);

    dispatch(v, &std::min_element);
    dispatch(v, &std::max_element);
    return 0;
}
//您的lambda作为函子
结构平均值
{
布尔运算符()(常量学生&a、常量学生&b)常量
{
返回a.get_average()

您的函数可以按如下方式编写:

template<typename Func>
Student dispatch(const std::vector<Student> &all_students, Func func)
{
    assert(!all_students.empty());
    return *func(std::begin(all_students), std::end(all_students), 
                 [](const Student &a, const Student &b){
                   return a.get_average() < b.get_average();});
}

另一种方法是始终在dispatch中调用
min_元素
,但传入具有不同行为的比较器

template<typename Comparator>
Student dispatch(const std::vector<Student> &all_students, Comparator comp)
{
    assert(!all_students.empty());
    return *std::min_element(std::begin(all_students), std::end(all_students), 
                             comp);
}

dispatch(students, std::less<Student>());
dispatch(students, std::greater<Student>());  // requires operator> for Student

在所有不同的选项中。

我的首选方法是将算法包装到lambda中,然后将lambda传递给模板函数。当您将其包装到宏中时,它有很好的语法:

#define LIFT(...)                                                  \
    ([](auto&&... args) -> decltype(auto) {                        \
        return __VA_ARGS__(std::forward<decltype(args)>(args)...); \
    })

template <typename Func>
Student dispatch(const std::vector<Student> &all_students, Func func){
  return *func(std::begin(all_students), std::end(all_students),
      [](const Student &a, const Student &b){
    return a.get_average() < b.get_average();});
}

// ...

std::cout<<"lowest: "<< dispatch(all_students, LIFT(std::max_element));
定义提升(…)\ ([](自动和…参数)->decltype(自动){\ 返回uu VA_ARGS_uuu(标准::转发(ARGS)…)\ }) 模板 学生派遣(const std::vector&all_学生,Func Func){ return*func(标准::开始(所有学生),标准::结束(所有学生), [](康斯特学生与a、康斯特学生与b){ 返回a.get_average()你能详细说明一下它是如何失效的吗?特别是请展示如何使用
分派
功能。如果同时计算最小值和最大值,请考虑。我应该更清楚,我意识到排序可能是最好的选择,但这只是学习C11的一个小演示程序。尽管我不喜欢定义,这是一个很好的魔法:)这看起来非常熟悉。使用,您还可以使用
ordered_by(MFLIFT(get_average))
代替lambda。
template<typename Func>
Student dispatch(const std::vector<Student> &all_students, Func func)
{
    assert(!all_students.empty());
    return *func(std::begin(all_students), std::end(all_students));
}

dispatch(students, 
         std::min_element<decltype(students)::const_iterator>);
dispatch(students, 
         std::max_element<decltype(students)::const_iterator>);
template<typename Comparator>
Student dispatch(const std::vector<Student> &all_students, Comparator comp)
{
    assert(!all_students.empty());
    return *std::min_element(std::begin(all_students), std::end(all_students), 
                             comp);
}

dispatch(students, std::less<Student>());
dispatch(students, std::greater<Student>());  // requires operator> for Student
auto minmax = std::minmax_element(std::begin(students), std::end(students));
#define LIFT(...)                                                  \
    ([](auto&&... args) -> decltype(auto) {                        \
        return __VA_ARGS__(std::forward<decltype(args)>(args)...); \
    })

template <typename Func>
Student dispatch(const std::vector<Student> &all_students, Func func){
  return *func(std::begin(all_students), std::end(all_students),
      [](const Student &a, const Student &b){
    return a.get_average() < b.get_average();});
}

// ...

std::cout<<"lowest: "<< dispatch(all_students, LIFT(std::max_element));