【问题标题】:Why does std::{container}::emplace not deduce its argument type?为什么 std::{container}::emplace 不推断其参数类型?
【发布时间】:2018-08-13 22:43:23
【问题描述】:

假设我有这个代码:

#include <string>
#include <unordered_set>

struct command_node {
    std::string key, value;
};

bool operator==(const command_node &x, const command_node &y) {
    return x.key == y.key;
}

namespace std {
    template<>
    struct hash<command_node> {
        typedef command_node argument_type;
        typedef size_t result_type;
        size_t operator()(const command_node &x) const {
            return std::hash<std::string>()(x.key);
        }
    };
}

using command_set = std::unordered_set<command_node>;

int main(int argc, char **argv)
{
    command_set commands;

    commands.emplace(
        command_node{"system", "running"}
    );

    return EXIT_SUCCESS;
}

它只是创建了一个 command_node 结构的 unordered_list。该代码仅用于说明。

问题:主要是这样(如上所示):

    commands.emplace(
        command_node{"system", "running"}
    );

但事实并非如此:

    commands.emplace(
        {"system", "running"}
    );

但是,如果我将 emplace 替换为 insert,则无论哪种方式都可以。换句话说,这是可行的:

    commands.insert(
        {"system", "running"}
    );

为什么 emplace 不推断 command_node

【问题讨论】:

  • 因为 emplace 函数都通过可变参数转发引用获取参数,这不会将大括号列表推断为任何内容。
  • 你应该使用commands.emplace("system", "running")
  • @Jaa-c 仅当容器中的类型不是聚合时才有效(当然,具有采用这些参数类型的构造函数)
  • @Jaa-c 这适用于上面的代码(这只是一个简单的演示),但不适用于我的实际项目代码,其中第二个参数(“运行”)被替换为容器本身。第二个参数是 initializer_list 发挥作用的地方。
  • @BlairFonville 您可以在“真实代码”中使用commands.emplace("system", Bar{x,y,z})。 Emplace 不是“递归的”。此外,这些大括号列表不是initializer_list s。

标签: c++ std


【解决方案1】:

这是因为基于转发引用的完美转发在大括号初始化列表中失败:对于编译器来说,这是一个“非推导上下文”。相反,将参数传递给容器的底层值类型构造函数。

插入方法不同:它们接受const value_type&amp; 左值引用或右值引用 (value_type&amp;&amp;)。因此,传递一个初始化类型的花括号初始化器列表效果很好。

【讨论】:

  • 这是有道理的。关于:“相反,将参数传递给容器的底层值类型构造函数” - 我实际上不能在我的实际代码中这样做,因为我的参数本身是用初始化列表构造的。但是,我明白你的意思。谢谢。
  • @lubgr 我们都最好遵守委员会约定的命名方式,并使用转发引用而不是通用引用open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4164.pdf
  • @SkepticalEmpiricist 这是一个很好的提示。我调整了术语。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 2014-02-04
  • 2019-02-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多