Как инициализировать кортеж неконструктивных по умолчанию не копируемых объектов?

Даны некоторые классы с параметризованными конструкторами, такими как:

class A
{
public:
    A(bool b, int i) { /*...*/ }
private:
    A(const A&) {}
};
class B
{
public:
    B(char c, double d) { /* ... */ }
private:
    B(const B&) {}
};

Как правильно инициализировать кортеж таких классов?

boost::tuple<A,B> tup( /* ??? */ );

Не использовать конструктор копирования A или B, и, если возможно, также не использовать move-constructor. Решение C++03 предпочтительнее, если это возможно.

2 ответа

Решение

Можете ли вы просто добавить кусочный конструктор для ваших типов? Если это так, вы можете создать ужасный макрос, который распаковывает и делегирует кортеж:

#define CONSTRUCT_FROM_TUPLE(CLS)                      \
    template <class... Ts>                             \
    CLS(std::tuple<Ts...> const& tup)                  \
        : CLS(tup, std::index_sequence_for<Ts...>{})   \
    { }                                                \
                                                       \
    template <class Tuple, size_t... Is>               \
    CLS(Tuple const& tup, std::index_sequence<Is...> ) \
        : CLS(std::get<Is>(tup)...)                    \
    { }

И просто добавьте его к своим типам:

struct A {
    A(bool, int ) { }
    A(const A& ) = delete;
    CONSTRUCT_FROM_TUPLE(A)
};

struct B {
    B(char, double ) { }
    B(const B& ) = delete;
    CONSTRUCT_FROM_TUPLE(B)
};

И передать в кортежи:

std::tuple<A, B> tup(
    std::forward_as_tuple(true, 42), 
    std::forward_as_tuple('x', 3.14));

До C++11, я не знаю, возможно ли это - у вас нет делегирующих конструкторов вообще. Вы должны либо:

  1. Написать свой tuple-подобный класс, который принимает кортежи в своем конструкторе
  2. Добавьте конструкторы кортежей к вашим типам, которые явно инициализируют то же самое, что и версии без кортежей
  3. Иметь кортеж типов, которые можно конструировать с одним аргументом, например boost::tuple<boost::scoped_ptr<A>, boost::scoped_ptr<B>>(new A(...), new B(...))

(1) много работы, (2) дублирование кода и подверженность ошибкам, и (3) теперь необходимо внезапно распределять ресурсы.

Вы можете использовать следующее:

tuple<A,B> tup(A(true, 42), B('*', 4.2));
Другие вопросы по тегам