std::map 默认值(仅移动类型)
std::map default value (move only types)
如何解决 std::map default value 仅移动类型的问题?看来问题是谁拥有这个对象
- 如果该值存在,则地图仍为所有者,并且
T const&
必须 returned
- 如果值不存在,调用者将是所有者,
T
(从默认值移动构造)必须 returned。
但是无论 return 值来自何处,函数的 return 类型必须相同。因此不可能从临时文件中获取默认值。我说得对吗?
您可以使用 std::shared_ptr,但那样会作弊。
这可以通过代理对象来实现。
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>
的默认复制构造函数会导致未定义的行为,因此我不得不定义一个非默认的复制和移动构造函数。
如何解决 std::map default value 仅移动类型的问题?看来问题是谁拥有这个对象
- 如果该值存在,则地图仍为所有者,并且
T const&
必须 returned - 如果值不存在,调用者将是所有者,
T
(从默认值移动构造)必须 returned。
但是无论 return 值来自何处,函数的 return 类型必须相同。因此不可能从临时文件中获取默认值。我说得对吗?
您可以使用 std::shared_ptr,但那样会作弊。
这可以通过代理对象来实现。
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>
的默认复制构造函数会导致未定义的行为,因此我不得不定义一个非默认的复制和移动构造函数。