std :: map默认值(仅移动类型)

时间:2018-10-27 15:22:19

标签: c++ default-value stdmap

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

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

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

您可以使用std :: shared_ptr,但是那样作弊。

1 个答案:

答案 0 :(得分: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<T>的默认副本构造函数会导致未定义的行为,因此我必须定义一个非默认副本并移动构造函数。