我可以使用 std::set 构造函数指定比较器而不指定所有模板参数吗
Can I specify comparator using std::set constructor without specifying all the template arguments
我想用 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
用于比较器)。并且仅采用比较器的映射构造函数不够智能,无法从比较器参数中获取键类型,也就是这不起作用:
std::set colors([](const Color& a, const Color& b){return a.name()<b.name();});
有没有办法指定我想要一组 Color
,但让构造函数指定比较器。
请注意,自 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:
如果我没记错的话,推导指南(在 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)); }
我想用 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
用于比较器)。并且仅采用比较器的映射构造函数不够智能,无法从比较器参数中获取键类型,也就是这不起作用:
std::set colors([](const Color& a, const Color& b){return a.name()<b.name();});
有没有办法指定我想要一组 Color
,但让构造函数指定比较器。
请注意,自 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:
如果我没记错的话,推导指南(在 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)); }