我可以将几个未指定返回类型的 std::function 放入 C++ 的容器中吗?如果可以,该怎么做?

问题描述 投票:0回答:1

我想用 C++ 编写一个通用排序器。我有一些这样的代码。

  template<typename T>
  class sorter {
  public:

    template<typename R>
    bool RegisterDimValueFetcher(const std::string &name, const std::function<R(const T &)> &f)
    {
      if (!f) {
        return false;
      }

      bool inserted = fetcher_map.insert(std::make_pair(name, f)).second;
      if (inserted) {
        priority_list.emplace_back(name);
      }
      return inserted;
    }

    bool AdjustPriority(const std::vector<std::string> &priorityList) {
      priority_list.assign(priorityList.begin(), priorityList.end());
      return priority_list == priorityList;
    }

    template<template<typename...> class C>
    bool sort(C<T> &collection, bool asc = true, typename std::enable_if<is_container<C<T>>::value>::type* = nullptr) {

      std::sort(collection.begin(), collection.end(), [&](const T &lRef, const T &rRef) {

        for (auto &dim : priority_list) {
          auto pair_iter = fetcher_map.find(dim);
          if (pair_iter != fetcher_map.end()
              && pair_iter->second) {

            auto l_val = pair_iter->second(lRef);
            auto r_val = pair_iter->second(rRef);

            if (l_val != r_val) {
              return asc ? std::less<R>()(l_val, r_val) : std::less<R>()(r_val, l_val);  // here using the template type R and it's obviously wrong.
            }
          }
        }
        return true;
      });
      return true;
    }

  private:
    std::unordered_map<std::string, std::function<R(const T &)>> fetcher_map; // template type R is not declared, but if it declared, current class could not support different return type
    std::vector<std::string> priority_list;

  };

我希望这段代码能够满足我的期望,使用代码如下:

struct Student {
  Student(const std::string &stuName, size_t stuAge)
    : name(stuName), age(stuAge) { }
  Student(const Student &ref)
    : name(ref.name), age(ref.age) { }

  std::string name;
  size_t age;
};

std::ostream &operator << (std::ostream &os, Student &stu) {
  os << "{name:" << stu.name << ", age:" << stu.age << "]";
  return os;
}

int func() {

  std::vector<Student> students;
  students.emplace_back(std::string("n1"), 36u);
  students.emplace_back(std::string("n2"), 36u);
  students.emplace_back(std::string("n2"), 37u);
  students.emplace_back(std::string("n3"), 2u);

  sorter<std::string, Student> gsorter;
  gsorter.RegisterDimValueFetcher("name", [](const Student &stu) {
      return stu.name;
      });
  gsorter.RegisterDimValueFetcher("age", [](const Student &stu) {
      return stu.age;
      //return std::to_string(stu.age);
      });

  gsorter.sort(students, false);
  for (auto &stu : students) {
    std::cout << stu << std::endl;
  }
  std::cout << std::endl;

  gsorter.AdjustPriority({"age", "name"});

  gsorter.sort(students);
  for (auto &stu : students) {
    std::cout << stu << std::endl;
  }

  return 0;
}

并得到如下内容的结果:

{name:n3, age:2}
{name:n2, age:37}
{name:n2, age:36}
{name:n1, age:36}

{name:n3, age:2}
{name:n1, age:36}
{name:n2, age:36}
{name:n2, age:37}

我尝试将 R 作为在模板类型 T 之后声明的模板类型,这导致返回类型更改为指定类型,如第二个 lambda 中的注释行。

任何人都可以帮助我改进代码吗?我的期望是使类排序器成为 mysql 中关键字“ORDER BY”的实现。

c++ templates sql-order-by
1个回答
0
投票

如果您存储(三向)comparers而不是getters,您可能会摆脱模板返回类型:

template<typename T>
class sorter
{
public:

    bool RegisterComparer(const std::string &name,
                          const std::function<int(const T&, const T&)> &f)
    {
      if (!f) {
        return false;
      }

      bool inserted = comparer_map.insert(std::make_pair(name, f)).second;
      if (inserted) {
        priority_list.emplace_back(name);
      }
      return inserted;
    }

    template<template<typename...> class C,
             typename std::enable_if<is_container<C<T>>::value, bool>::type = false >
    bool sort(C<T> &collection, bool asc = true) const {
        std::sort(collection.begin(), collection.end(), [&](const T &lRef, const T &rRef) {
            for (auto &dim : priority_list) {
                auto pair_iter = comparer_map.find(dim);
                if (pair_iter != comparer_map.end() && pair_iter->second) {
                    const auto comp = (pair_iter->second)(lRef, rRef) * (asc ? 1 : -1);
                    if (comp == 0) continue;
                    return comp < 0;
                }
            }
            return false;
      });
      return true;
    }

private:
    std::unordered_map<std::string, std::function<int(const T&, const T&)>> comparer_map;
    std::vector<std::string> priority_list;
};
sorter<Student> gsorter;
gsorter.RegisterComparer("name", [](const Student &lhs, const Student &rhs) {
      return lhs.name.compare(rhs.name);
    });
gsorter.RegisterComparer("age", [](const Student &lhs, const Student &rhs) {
      return (int) lhs.age - (int) rhs.age;
    });

演示

© www.soinside.com 2019 - 2024. All rights reserved.