我想用lambda比较器构造一个集合。
由于已知的限制,您不能将lambda指定为模板参数(您需要decltype()
它)所以我考虑在模板参数列表中指定映射的键,并在构造函数参数中指定比较器。
类似的东西:
std::set<Color> colors({ { "Red", 255, 0 , 0 }, { "Green", 0,255,0 }, { "Black", 0,0,0 } } , [](const Color& a, const Color& b){return a.name()<b.name();});
但是,一旦我指定了模板参数(<Color>
),我就会从错误消息中理解,我强迫其他人默认(std::less
用于比较器)。只使用比较器的地图构造函数不够智能,无法从比较器参数中获取Key类型,也就是说这不起作用:
std::set colors([](const Color& a, const Color& b){return a.name()<b.name();});
有没有办法指定我想要一组Color
s,但让比较器由构造函数指定。
请注意,我可以使用构造函数来推导自C ++ 17以来的模板类型,但它并不漂亮,因为我需要编写比我想要的更多的东西。
std::set colors(std::initializer_list<Color>{ { "Red", 255, 0 , 0 }, { "Green", 0,255,0 }, { "Black", 0,0,0 } } , [](const Color& a, const Color& b){return a.name()<b.name();}, std::allocator<char/*???*/>{});
完整代码here:
答案 0 :(得分:2)
如果我没记错的话,扣除指南(在C ++ 17中)是不可能显式的模板类型并推断出其他的。
如果你想从lambda比较器推导出类型Color
,我能想象的最好是创建一个makeSetFromCmp()
函数
template <typename Key>
auto makeSetFromCmp (bool(*cmp)(Key const &, Key const &),
std::initializer_list<Key> const & il)
{ return std::set(il, cmp); }
诀窍是首先传递比较器,Key
类型可以从比较器中推断出来,因此不需要显式std::initializer_list<Key>
来调用函数。
所以你可以写
auto colors = makeSetFromCmp(+[](Color const & a, Color const & b)
{ return a.name() < b.name(); },
{ { "Red", 255, 0 , 0 },
{ "Green", 0,255,0 },
{ "Black", 0,0,0 } });
在lambda定义之前观察+
:在一个好旧的函数指针中转换lambda。
makeSetFromCmp()
的一个小改进版本(带有第三个分配器模板参数,默认值和转发)可能
template <typename Key, typename A = std::allocator<Key>>
auto makeSetFromCmp (bool(*cmp)(Key const &, Key const &),
std::initializer_list<Key> && il,
A && all = A{})
{ return std::set(std::forward<std::initializer_list<Key>>(il),
cmp,
std::forward<A>(all)); }