如何解决仅移动类型的std::map default value?似乎问题出在谁拥有对象
T const&
T
(从默认值移动构造)。但是,无论返回值来自何处,函数的返回类型都必须相同。因此,不可能从临时值中获取默认值。我说得对吗?
您可以使用std :: shared_ptr,但是那样作弊。
答案 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>
的默认副本构造函数会导致未定义的行为,因此我必须定义一个非默认副本并移动构造函数。