带比较器的映射构造函数

Map constructor with comparator

class cmp{  // simple comparison function
public:
    bool operator()(const int x,const int y)
    { return x > y; }
};

当我使用 compare 对象调用任何 stl 算法(如 std::sort)时,它工作正常。

std::sort(vec.begin(), vec.end(), cmp());

但对于 stl 容器,这并不相似。

std::map<int, int> mp(cmp()); // Not working
std::map< int, int, cmp> mp;  // Works fine. 

此外,对于 lambda 表达式,

auto lamda = [](cont int x, const int y)
{ return x > y; };

std::map<int, int, bool(*)(int, int)> mp(lamda); //Works
std::map<int, int > mp(lambda); // not working

谁能解释一下区别?

您在此处尝试使用的构造函数是:

explicit map( const Compare& comp, const Allocator& alloc = Allocator());

然而,它被声明为 explicit 的事实意味着它无法推断出 Compare 的温度,并且您必须在启动它时手动输入比较器的类型。


旁注:
我相信对于你的仿函数,它需要是一个 const 成员函数。

这个有效:

std::sort(vec.begin(), vec.end(), cmp());

因为函数模板可以从提供的参数中推断出它们的模板参数。对于 stl 容器,这不起作用,因为您没有调用模板函数,而是声明了 class 模板的特化。

std::map<int, int> mp(cmp()); // Not working
std::map< int, int, cmp> mp; // Works fine.

对于 classes,如果您显式提供任何模板参数,则必须全部提供(对于 c++17 之前的版本,您必须提供句点。)Compare 模板参数(第三个参数)默认为 std::less<Key> 除非您另有说明,如您的示例所示。

C++就是这样。你没有做错任何事,但想要省略该参数是行不通的。

您的 lambda 示例有相同的解释。

C++17 添加了 Class 模板参数推导 (CTAD),它仅在您允许它推导(或默认)所有 模板参数时才有效。您不能明确提供任何内容,或者 CTAD 已禁用。使用 CTAD 是可能的,但不可取。 例如,您可以这样声明一个映射:

std::map m{{std::pair{0, 0}}, std::greater<>{}};

但是 1) 这相当丑陋,并且可能比它试图解决的问题更糟糕,并且 2) 它创建了包含初始元素的地图。唯一可能工作的其他构造函数是,如果您已经有一个具有正确 key/value 类型的现有映射,并在其中向构造函数提供一个空的迭代器范围以创建一个空对象副本。

// also possible, assuming you have m1, you can use an 
// empty range (from end to end, for example)
std::map<int, int> m1;

// CTAD works here but will make people blink when they see it
std::map m2{end(m1), end(m1),  std::greater<>{}};

但这是一种人为的情况。如果您还没有 m1,那么它并不是真正的解决方案。需要明确的是,我不是在建议这样做,只是为了完整性而提及它。

简而言之,除非您想要做体操并创建一个残暴的代码,否则您应该只提供比较的类型作为容器的模板参数。