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

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

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 и, если возможно, не использовать конструктор перемещения. Предпочтительно решение С++ 03, если это возможно.


person shrike    schedule 06.04.2016    source источник
comment
Для вашего редактирования вы можете посмотреть why-is-there-no-piece- кортеж-конструкция   -  person Jarod42    schedule 07.04.2016
comment
Если вы можете сделать свои типы подвижными, вы должны это сделать. Есть очень мало случаев, когда тип не должен быть подвижным. (В стандартной библиотеке атомарные объекты, мьютексы и условные переменные не могут перемещаться по техническим причинам.) Если вы не можете сделать ваши типы перемещаемыми, вы можете использовать std::unique_ptr<A> в качестве обходного пути.   -  person Brian Bi    schedule 07.04.2016
comment
@Brian: move-constructor - это возможный вариант, которого я бы предпочел избегать, чтобы мой код можно было скомпилировать на компиляторе, не совместимом с C ++ 11. Спасибо за ответ в любом случае.   -  person shrike    schedule 07.04.2016
comment
Итак... std::tuple в порядке, но конструкторы перемещения - нет?   -  person Brian Bi    schedule 07.04.2016
comment
@Brian: Он использовал boost-tuples в своем теге.   -  person Nicol Bolas    schedule 07.04.2016
comment
@Brian: да, с использованием кортежей boost и компилятора vc10   -  person shrike    schedule 07.04.2016
comment
Если вам нужно решение C++03, вы должны указать это в своем вопросе. То же самое касается конкретного компилятора.   -  person M.M    schedule 07.04.2016
comment
@MM: извините, я действительно должен был четко указать, что решение C ++ 03 предпочтительнее (хотя и не обязательно) для решения C ++ 11.   -  person shrike    schedule 07.04.2016
comment
@Jarod: спасибо за ссылку, думаю, я перейду на vc14...   -  person shrike    schedule 07.04.2016


Ответы (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) требует внезапного выделения памяти.

person Barry    schedule 06.04.2016
comment
К вашему сведению: он использовал boost-tuples в качестве тега, поэтому std::tuple не является целью. - person Nicol Bolas; 07.04.2016
comment
@Nicol Было бы здорово, если бы намерение было полностью изложено в вопросе за один раз, а не постепенно в различных комментариях ... - person Barry; 07.04.2016
comment
@Barry: я думал, что теги прояснят это (нет тега C++ 11, тег boost-tuple), но я ошибался, извините. В любом случае, спасибо за все доступные решения, которые вы предоставили, я, вероятно, выберу решение 3, пока не перейду на С++ 11. Большое спасибо. - person shrike; 07.04.2016

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

tuple<A,B> tup(A(true, 42), B('*', 4.2));
person Jarod42    schedule 06.04.2016
comment
Спасибо за ответ. Я забыл упомянуть, что нельзя использовать конструктор копирования. Вопрос отредактирован. В любом случае, спасибо за ваш ответ. - person shrike; 07.04.2016
comment
Обратите внимание, что он будет использовать конструктор перемещения, если это возможно. - person Jarod42; 07.04.2016