стандартное значение std :: map (перемещать только типы) - PullRequest
0 голосов
/ 27 октября 2018

Как определить значение std :: map по умолчанию для типов только для перемещения?Кажется, что проблема в том, кто владеет объектом

  • Если значение существует, карта остается владельцем, и T const& должно быть возвращено
  • Если значение не выходит,вызывающий будет владельцем, и должен быть возвращен T (сконструированный на основе значения по умолчанию).

Но тип возвращаемого значения функции должен быть одинаковым независимо от того, где находитсявозвращаемое значение пришло от.Таким образом, невозможно взять значение по умолчанию из временного.Я прав?

Вы можете использовать std :: shared_ptr, но это будет обманом.

1 Ответ

0 голосов
/ 28 октября 2018

Этого можно достичь с помощью прокси-объекта.

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> вызывает неопределенное поведение, поэтому мне пришлось определить конструкторы копирования и перемещения не по умолчанию.

...