【问题标题】:override map::compare with lambda function directly直接覆盖 map::compare 与 lambda 函数
【发布时间】:2013-08-04 16:47:26
【问题描述】:

尝试使用 lambda 覆盖 map::compare 函数,似乎以下解决方案有效。

auto cmp = [](const int&a, const int& b) { return a < b; };
std::map<int, int, decltype(cmp)> myMap(cmp);

但是,我必须先定义cmp,然后再使用它。
我可以在不定义“cmp”的情况下执行此操作吗?

【问题讨论】:

  • cmp 不是函数指针。
  • 什么ints 已经相互比较了。你想做什么?为什么不想使用函数?
  • 是的,函数指针不是一个准确的术语。编辑问题以使问题更清晰。
  • 那么你使用什么方法失败了?我们知道您想要的不是您的榜样,而是您的最终目标。
  • 但是不能将无捕获的lambas转换为函数指针吗?

标签: c++ c++11 map lambda


【解决方案1】:

不,您不能在未评估的上下文中使用 lambda - 即示例中的模板参数。 所以你必须在其他地方定义它(使用auto),然后使用decltype...另一种方式,正如已经提到的那样,使用“序数”仿函数

如果您的问题是关于“如何在定义映射时使用 lambda 表达式 *一次*”,您可以利用 lambda 到 std::function 的隐式转换,如下所示:

#include <iostream>
#include <functional>
#include <map>

int main()
{
    auto m = std::map<int, int, std::function<bool(const int&, const int&)>>{
        [](const int& a, const int& b)
        {
            return a < b;
        }
    };
    return 0;
}

您可以为 map 类型引入别名以减少以后的输入...

【讨论】:

  • 但是,使用std::function 会增加一个间接级别并降低其效率。
【解决方案2】:
#include <iostream>
#include <functional>
#include <map>
#include <typeinfo>

typedef std::map< int, int, std::function<bool(const int&, const int&)> > MyMap;

int main()
{
    auto cmp = [](const int& a, const int& b) { return a < b; };
    MyMap map(cmp);

    return 0;
}

使用 std::function 为比较器类型提供适当的类型签名,您可以定义映射类型,然后分配您希望的任何 lambda 比较。

【讨论】:

  • 这是 OP 所要求的,但实际上,引入 std::function 感觉像是一个糟糕的解决方案。代替别名模板怎么样? template&lt;typename Comp&gt; using MyMap = std::map&lt;int, int, Comp&gt;; 然后在实例化地图之前不必定义比较器。
  • @Praetorian 我被一个不支持模板别名的劣质编译器(VS2012)困住了,所以我没有使用它们的经验。
  • 模板别名无论如何都无济于事:你不能在未评估的上下文中使用 lambda,但无论如何你必须指定一个 Comp 参数(在实例化点)。
  • 但您可以在模板别名中使用 std::function 。例如,请参阅我的帖子。我实际上认为 std::function 如果有令人信服的理由来处理具有许多不同比较器的多个映射,特别是如果一些映射捕获一个变量(在这种情况下可能存在任意数量的唯一比较),则不是一个糟糕的解决方案。
【解决方案3】:

你可以做这样的事情,地图的类型是从你传递给函数的函数中推断出来的。

#include <map>

template<class Key, class Value, class F>
std::map<Key, Value, F> make_map(const F& f) {
    return std::map<Key, Value, F>{f};
}

int main() {
    auto my_map = make_map<int, int>([](const int&a, const int& b) { return a < b; });
    my_map[10] = 20;
}

我看不出这样做的很多理由,但我不会说它没用。通常,您需要一个已知的比较器,以便可以轻松地传递地图。通过上面的设置,您可以一直使用模板函数,如下所示

tempalte<class F>
void do_somthing(const std::map<int, int, F>& m) {

}

这不一定是坏事,但我的直觉告诉我,拥有一个只能由泛型函数处理的类型是不好的。我认为它适用于 lambda 函数,但仅此而已。这里的解决方案是使用 std::function

#include <map>
#include <functional>

template<class Key, class Value>
using my_map_t = std::map<Key, Value, std::function<bool(const Key&, const Key&)>>;

int main() {
    my_map_t<int,  int> my_map{[](const int&a, const int& b) { return a < b; }};
    my_map[10] = 20;
}

现在你可以使用任何你想要的谓词并且你有一个具体的类型可以使用,my_map

希望这会有所帮助!

【讨论】:

    【解决方案4】:

    在 C++20 中你可以做到this:

    std::map<int, int, decltype([](const int&a, const int& b) { return a < b; })> myMap;
    
    
    int main() {
        myMap.insert({7, 1});
        myMap.insert({46, 2});
        myMap.insert({56, 3});
        for (const auto& [key,value]:myMap) {
            std::cout <<  key <<  "  " << value << std::endl;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多