Рассмотрим следующий код C ++ 03 (я должен сделать код совместимым с компиляторами до C ++ 11):
// This class belongs to a third-party SDK and cannot be touched
class A {
public:
explicit A();
explicit A(bool b);
private:
// Non-copyable
A(const A&);
const A& operator= (const A&);
}
boost::container::map<int, A> myMap;
Здесь используется карта Boost, потому что она позволяет использовать ее даже в C ++ 03. Проблема в том, что я могу безошибочно использовать emplace-construct в карту, используя конструктор с одним аргументом, но я не знаю, как создать объект по умолчанию, как показано в следующем коде:
myMap.emplace(1, true); // Works
myMap.emplace(1); // Fails
Второй вызов завершается неудачно, потому что он воспринимается как вызов перегрузки emplace (std :: pair …), поэтому кажется, что нет способа «default-emplace».
Есть ли способ добиться того, чего я хочу?
Из интереса я играл с этим
Как важный источник данных, я знал, что std::map
(в C ++ 11) поддерживает кусочная конструкция из его пар значений:
std::map<int, A> stdMap;
stdMap.emplace(std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple());
поэтому вызвал бы нужный вам конструктор. Тем не менее, так или иначе, то же самое не сразу работает для Boost’s map
, Хммм.
Тем не менее, это пробудило мой интерес: повышение использует std::pair<const K, V>
как тип значения ?!
boost::container::map<int, A>::value_type p {
std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple(true)
};
работает без проблем. И я также могу убедиться, что этот typedef по факту тип хранится:
static_assert(std::is_same<decltype(p), std::remove_reference<decltype(*myMap.begin())>::type>::value, "Nonstandard pair");
Таким образом, это начинает выглядеть как ошибка в пересылке через реализацию целочисленного дерева, когда он использует allocator::construct
вызов.
Делая A
перемещается, но не копируется, а затем перемещает объект в функцию размещения.
В C ++ 03 вы можете использовать Boost.Move делать A
подвижны. Пример:
#include <boost/container/map.hpp>
#include <boost/move/move.hpp>
#include <cassert>
class A {
BOOST_MOVABLE_BUT_NOT_COPYABLE(A)
public:
explicit A() {};
explicit A(bool b) {};
A(BOOST_RV_REF(A)) {}
A& operator=(BOOST_RV_REF(A)) { return * this; }
private:
// Non-copyable
// A(const A&);
// const A& operator= (const A&);
};int main()
{
boost::container::map<int, A> myMap;
myMap.emplace(1, true); // Works
A a;
myMap.emplace(1, boost::move (a));
// myMap.emplace(1); // Fails
}
Добавлена поддержка piecewise_construct для Boost 1.62. Итак, следующий код:
#include <boost/container/map.hpp>
#include <boost/tuple/tuple.hpp>
// This class belongs to a third-party SDK and cannot be touched
class A
{
public:
explicit A(){}
explicit A(bool b);
private:
// Non-copyable
A(const A&);
const A& operator= (const A&);
};
int main()
{
using namespace boost::container;
map<int, A> myMap;
myMap.emplace(piecewise_construct, boost::tuple<int>(1), boost::tuple<>());
return 0;
}
должен работать в компиляторах C ++ 03 и C ++ 11 +.