【问题标题】:Can I specify comparator using std::set constructor without specifying all the template arguments我可以在不指定所有模板参数的情况下使用 std::set 构造函数指定比较器吗
【发布时间】:2018-01-08 17:25:21
【问题描述】:

我想用 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();});

但是根据我从错误消息中了解到的信息,我一指定模板参数(&lt;Color&gt;)就强迫其他人默认(std::less 用于比较器)。而且仅采用比较器的映射构造函数不够聪明,无法从比较器参数中获取 Key 类型,也就是这不起作用:

std::set colors([](const Color& a, const Color& b){return a.name()<b.name();});

有没有办法指定我想要一组Colors,但是让构造函数指定比较器。

请注意,从 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++ templates stl c++17 template-argument-deduction


    【解决方案1】:

    如果我没记错的话,推导指南(在 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&lt;Key&gt; 调用函数。

    所以你可以写

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

    【讨论】:

    • 啊,我很害怕......顺便说一句,我认为提升可调用特征可以让你消除对 + 的需要(你可以通过可调用和元黑客来获取参数类型)但总的来说这个答案非常好......所以如果没有人很快提出更好的答案,我会接受它。
    猜你喜欢
    • 2011-02-21
    • 2019-11-24
    • 1970-01-01
    • 1970-01-01
    • 2021-07-05
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2015-05-05
    相关资源
    最近更新 更多