【问题标题】:std::map default value (move only types)std::map 默认值(仅移动类型)
【发布时间】:2019-04-01 01:55:58
【问题描述】:

对于只移动类型如何解决std::map default value?似乎问题在于谁拥有该对象

  • 如果值存在,则地图保持所有者身份,并且必须返回 T const&
  • 如果值不存在,调用者将是所有者,并且必须返回一个T(从默认值移动构造)。

但是无论返回值来自哪里,函数的返回类型都必须相同。因此,不可能从临时获取默认值。我说的对吗?

你可以使用 std::shared_ptr 但那是作弊。

【问题讨论】:

  • [] 运算符肯定会返回一个引用,并且基于迭代器的访问不会移动或复制任何内容,除非您编写代码来执行此操作。那你到底在问什么? [] 运算符将默认构造值类的实例,随后的赋值将对其进行移动赋值。所以,只要你的类有一个默认构造函数和一个移动赋值运算符,你就大功告成了。
  • 地图不得更新。它应该是 const 方法,如果存在则返回 map 中已经存在的内容,否则它应该返回指定的默认值。
  • 没有这样的std::map 方法。您必须自己实现此功能,方法是使用find(),然后使用找到的值,或使用默认值。 C++ 中很少有魔术按钮可以通过按下来完成您想要的操作。其中有一些,但如果它们都没有做你需要做的事情,你必须自己用 C++ 发明和构建这个神奇的按钮。我认为您想要做的是使用一个助手类,该类将拥有该值的默认实例,或者返回对地图中的那个的引用,并让您的自定义查找代码相应地实例化它。
  • 您链接的问题中给出的答案有什么问题?
  • @user877329 为什么需要使用临时源?例如,你可以在你的函数中有一个static T default_value; 并返回一个对它的引用。

标签: c++ default-value stdmap


【解决方案1】:

这可以通过代理对象来实现。

template <typename T>
class PossiblyOwner
{
public:
    struct Reference {};

    PossiblyOwner(const PossiblyOwner & other)
       : m_own(other.m_own), 
         m_ref(m_own.has_value() ? m_own.value() : other.m_ref)
    {}
    PossiblyOwner(PossiblyOwner && other)
       : m_own(std::move(other.m_own)), 
         m_ref(m_own.has_value() ? m_own.value() : other.m_ref)
    {}

    PossiblyOwner(T && val) : m_own(std::move(val)), m_ref(m_own.value()) {}
    PossiblyOwner(const T & val) : m_own(val), m_ref(m_own.value()) {}
    PossiblyOwner(Reference, const T & val) : m_ref(val) {}
    const T& value () const { return m_ref; }
    operator const T& () const { return m_ref; }

    // convenience operators, possibly also define ->, +, etc. 
    // but they are not strictly needed
    auto operator *() const { return *m_ref; }
private:
    std::optional<T> m_own;
    const T & m_ref;
};

// Not strictly required
template <typename T>
std::ostream & operator<<(std::ostream & out,
              const PossiblyOwner<T> & value)
{
    return out << value.value();
}
template <typename Container, typename Key, typename ...DefaultArgs>
auto GetOrDefault(const Container & container, const Key & key,
                  DefaultArgs ...defaultArgs)
    -> PossiblyOwner<decltype(container.find(key)->second)>
{
    auto it = container.find(key);
    using value_type = decltype(it->second);
    using ret_type = PossiblyOwner<value_type>;
    if (it == container.end())
        return {value_type(std::forward<DefaultArgs>(defaultArgs)...)};
    else
        return {typename ret_type::Reference{}, it->second};
}

那么用法可以是:

int main()
{
    std::map<int, std::unique_ptr<std::string>> mapping;
    mapping.emplace(1, std::make_unique<std::string>("one"));
    mapping.emplace(2, std::make_unique<std::string>("two"));
    mapping.emplace(3, std::make_unique<std::string>("three"));
    std::cout << *GetOrDefault(mapping, 0,
                 std::make_unique<std::string>("zero")) << "\n";
    std::cout << *GetOrDefault(mapping, 1,
                 std::make_unique<std::string>("one1")) << "\n";
    std::cout << *GetOrDefault(mapping, 3,
                 new std::string("three1")) << "\n";
}

编辑

我注意到PossiblyOwner&lt;T&gt; 的默认复制构造函数会导致未定义的行为,因此我必须定义一个非默认复制和移动构造函数。

【讨论】:

    猜你喜欢
    • 2011-05-30
    • 2011-01-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2021-12-23
    • 2017-05-31
    相关资源
    最近更新 更多