我可以使用std :: set构造函数指定比较器,而无需指定所有模板参数

时间:2018-01-08 17:25:21

标签: c++ templates stl c++17 template-deduction

我想用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

1 个答案:

答案 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)); }