STL关联容器:擦除和取回(不可复制的)元素

int*_*lfx 5 c++ templates stl c++11

我正在使用STL关联容器(std::setstd::map)与持有std::unique_ptr<>实例的键.关键定义等同于以下内容:

struct Key
{
    std::unique_ptr<Object> object;
    bool operator== (const Key& rhs) const { return object->equal (*rhs.object); }
    bool operator<  (const Key& rhs) const { return object->less (*rhs.object); }
}
Run Code Online (Sandbox Code Playgroud)

众所周知,STL关联容器(特别是自C++ 11以来)没有办法获得对要移动的键的非const引用.我的密钥是不可复制的,所以c ++:从容器中删除元素并将其取回不起作用.

是否有非UB方法来克服这个问题?

我目前的解决方案如下:

template <typename T>
using map_pair_type = std::pair<typename T::key_type, typename T::mapped_type>;

template <typename T>
typename T::value_type take_set (T& container, typename T::iterator iterator)
{
    typename T::value_type result = std::move (const_cast<typename T::value_type&> (*iterator));
    container.erase (iterator);
    return result;
}

template <typename T>
map_pair_type<T> take_map (T& container, typename T::iterator iterator)
{
    map_pair_type<T> result {
        std::move (const_cast<typename T::key_type&> (iterator->first)),
        std::move (iterator->second)
    };
    container.erase (iterator);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

How*_*ant 7

这是其中之一:

真对不起.我们试图通过委员会来完成这项工作.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3586.pdf

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3645.pdf

据我所知,你的解决方案是最好的.您的地图解决方案确实显示未定义的行为 如果第二步引发异常,那将会非常糟糕.除此之外,我怀疑它会起作用.而且我怀疑我会因为这样说而投票.

UB的原因是键被定义为const(而不是仅仅被const引用引用).const在那种情况下抛弃(并且有一个移动构造函数修改对象)是UB.

如果N3586被接受,你可以:

move_only_type mot = move(*s.remove(s.begin()));
Run Code Online (Sandbox Code Playgroud)

要么:

move_only_key mok = move(m.remove(m.begin())->first);
Run Code Online (Sandbox Code Playgroud)

N3586/N3645在委员会中表现出色.它是通过工作组阶段进行讨论和完成的,只是在全体委员会中被击落.关注的是std :: lib必须提交UB才能实现它.它尚未重新提交.

更新

现在可以在C++ 17中执行此操作,但是调用成员函数extract而不是remove.