【问题标题】:Why do we need piecewise_construct in map emplace in C++20?为什么我们需要在 C++20 中的 map emplace 中使用 piecewise_construct?
【发布时间】:2020-05-12 17:04:51
【问题描述】:

这是关于 std::map emplace 函数的潜在重载的理论问题,该函数检测到它已被传递 2 个元组,而不是 C++20 中是否存在此功能的问题。

根据我在之前的question 中看到的情况,map emplace 是 std::pair 问题的“受害者”。

这让我想知道为什么只有当我们将 2 个元组传递给 emplace(并且键/值可以从各自的元组构造)时,map emplace 没有概念/SFINAE 重载才有效。

我想到的原因:

  • 将 std::tuple 作为构造函数的参数的怪异类(也可能具有将该元组类型扩展为普通参数的 ctor)
  • 没有人认为值得花时间通过解决一个特定问题来节省一点打字时间

【问题讨论】:

    标签: c++ sfinae c++20 c++-concepts


    【解决方案1】:

    将 std::tuple 作为构造函数参数的怪异类

    是的,没错。

    如果您决定 m.emplace(x, y) 自动 为元组 xy 执行分段构造功能,那么我就不可能构造这个:

    struct Key { Key(std::tuple<int, int>); bool operator<(Key const&) const; };
    struct Value { Value(std::tuple<char>); };
    map<Key, Value> m;
    m.emplace(std::tuple(1, 2), std::tuple('3'));
    

    我需要为这两种类型提供tuples,但我总是Key 提供两个ints,为Value 提供一个char,但这并没有不行。我必须要么为Key 添加一个额外的构造函数,要么不做任何安放。

    现在,如果你跟进说,好吧,如果 xy 是元组,m.emplace(x, y) 将自动执行 piecewise_construct 而且分段构造实际上是有效的。 . 然后,首先,这变得相当复杂。但是,如果两种结构都有效呢?

    struct Key2 {
        Key2(std::tuple<int, int>);
        Key2(int, int);
        bool operator<(Key2 const&) const;
    };
    map<Key2, Value> m2;
    m2.emplace(std::tuple(1, 2), std::tuple('3'));
    

    现在这总是使用(int, int) 构造函数。这是用户在这里的意图吗?

    基本上,将它们分开意味着用户可以做他们需要的事情并且没有歧义。

    【讨论】:

    • 很好的答案,但对于最后一部分:标准可以说 STL 需要对歧义进行静态断言并警告用户使用分段标记,但我不知道标准是否曾经这样做(告诉STL 来检测奇怪的用例并通知用户)。
    • @NoSenseEtAl 请记住,“怪异类”包括std::tupleKey2 的行为与此处的 std::tuple&lt;int, int&gt; 完全相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-15
    • 1970-01-01
    • 1970-01-01
    • 2016-02-21
    • 1970-01-01
    • 1970-01-01
    • 2012-12-20
    相关资源
    最近更新 更多