C++: Полиморфный контейнер, который может добавить несколько объектов сразу

Попытка повторно учесть некоторую инфраструктуру кодирует, я решил использовать наследование, чтобы достигнуть полиморфного поведения между несколькими классами. Следующий шаг должен добавить их к контейнеру, повторить по ним и DoSomething ();

Мое текущее строительство контейнера неуклюже. Даже если я использую это изящный решение для контейнера, строительство - все еще беспорядок.

vector> vec;

vec.push_back(unique_ptr(new ChildA(var1, var2)));
vec.push_back(unique_ptr(new ChildB(var3, var4)));
vec.push_back(unique_ptr(new ChildC(var5, var6)));

ChildA, ChildB и ChildC все полиморфные друг другу. Var1... var6 могут быть от различных типов и требуются для создания дочерних объектов.

Я хотел бы создать этот вектор в нескольких местах для использования. Проблема состоит в том, что количество детей может измениться и следовательно данные, в которых дети нуждаются для строительства. Пытаясь идти путь stdarg.h, подведенного, так как, это не поддерживается:

if     !defined(_WIN32)
#error ERROR: Only Win32 target supported!
#endif

Как вы осуществили бы метод фабрики, который строит это множество?

ОБНОВЛЕНИЕ, требуемое решение:

vec = CreatePolyVec(var1, var2, typeInfo1, var3, var4, typeInfo2, var5, var6 typeInfo3);
vec = CreatePolyVec(var1, var2, typeInfo1, var3, var4, typeInfo2);

линия 1 создаст то же самое множество как выше. линия 2 снова использует тот же самый код, чтобы создать подобный вектор, но с одним меньшим количеством объекта. Typeinfo содержит информацию, требуемую создать объект.

Это - основное решение, более продвинутый проведет в жизнь список аргументов во время компиляции. например, следующее требование к функции не имеет смысла:

vec = CreatePolyVec(var1, var2,typeinfo1, var3, var4, typeinfo2, var5);

недостаточно параметров, чтобы создать последний дочерний объект.

2
nl ja de
Чтение обновления..., которое, вероятно, необходимо искать, как сделать "прекрасное отправление".
добавлено автор Martin Ba, источник
Чтение обновления..., которое, вероятно, необходимо искать, как сделать "прекрасное отправление".
добавлено автор Martin Ba, источник
Вы C++ поддержки компилятора 11 variadic шаблонов?
добавлено автор Angew, источник
Можно ли обеспечить вариант использования в качестве примера (в коде) требуемого решения?
добавлено автор Angew, источник
станд.:: вектор <...> args и затем вы повторяете через ваш вектор , чтобы создать ваши элементы через фабрики или прямых конструкторов? Или возможно я didn' t получают вашу проблему, я don' t вполне понимают то, чего вы хотите достигнуть в конце.
добавлено автор Mic, источник
станд.:: вектор <...> args и затем вы повторяете через ваш вектор , чтобы создать ваши элементы через фабрики или прямых конструкторов? Или возможно я didn' t получают вашу проблему, я don' t вполне понимают то, чего вы хотите достигнуть в конце.
добавлено автор Mic, источник
Ваше заявление - WinRT или.NET применение? Это может быть, причина?
добавлено автор Lazin, источник
Ваше заявление - WinRT или.NET применение? Это может быть, причина?
добавлено автор Lazin, источник
@MartinBa: За исключением того, что emplace_back протекает, когда вектор не перераспределяет. Лучший выбор состоял бы в том, чтобы написать make_unique (см. Траву Sutter' s блог) и использование это.
добавлено автор Sebastian Redl, источник
@MartinBa: За исключением того, что emplace_back протекает, когда вектор не перераспределяет. Лучший выбор состоял бы в том, чтобы написать make_unique (см. Траву Sutter' s блог) и использование это.
добавлено автор Sebastian Redl, источник
Я предполагаю, что var1 к var6 не все одинаковые тип. Как действительно делают вас, знают который тип объектов создать (ChildA, ChildB, ChildC)?
добавлено автор ymett, источник
Я предполагаю, что var1 к var6 не все одинаковые тип. Как действительно делают вас, знают который тип объектов создать (ChildA, ChildB, ChildC)?
добавлено автор ymett, источник
Рефакторинг @ymett, один момент - Ищет. Если у вас есть лучшая идея. не стесняйтесь давать ответ.
добавлено автор qballer, источник
Рефакторинг @ymett, один момент - Ищет. Если у вас есть лучшая идея. не стесняйтесь давать ответ.
добавлено автор qballer, источник
Эй парни не стесняются отвечать и разделять примеры.
добавлено автор qballer, источник
Эй парни не стесняются отвечать и разделять примеры.
добавлено автор qballer, источник
Я тащу от земли окон, пишу я в C++.
добавлено автор qballer, источник
Я тащу от земли окон, пишу я в C++.
добавлено автор qballer, источник
Мой компилятор - VS2012
добавлено автор qballer, источник
Мой компилятор - VS2012
добавлено автор qballer, источник

3 ответы

Есть две проблемы здесь, 1. То, как решить то, что печатает каждого ребенка, будет, и 2. Как создать многократных детей.

Решить который ребенок создать

Это может быть сделано во время компиляции или время выполнения. Чтобы сделать это во время компиляции, вам нужны шаблоны.

template
vector> CreateVec(Arg1&& arg1, Arg2&& arg2)
{
    vector> result;
    result.push_back(unique_ptr(
        new Child(std::forward(arg1), std::forward(arg2))));
    return result;
}

called as follows CreateVec(myArg1, myArg2).

Если необходимо решить во времени выполнения, можно использовать карту фабричных функций, внесенных в указатель динамической переменной. Или вы могли использовать указатель на объект фабрики как ваша динамическая переменная.

Создать многократных детей

Здесь у вас есть выбор между цепочечными функциями и variadic шаблонами.

Цепочечные функции

Это по существу, что делает iostreams. Имейте свою функцию, которая создает вектор и добавляет, что холостой ребенок возвращает объект, который позволяет вам добавлять второго ребенка и возвращает себя разрешающий вам продолжиться.

Проблема здесь состоит в том, что вы хотите, чтобы функция возвратила вектор, таким образом, это не может также возвратить другой объект. Вы могли использовать оператор преобразования, чтобы получить вектор, или явная функция, но вероятно самый легкий должна создать вектор сначала, и просто использовать функции, чтобы добавить детей.

class AddChildren
{
    vector>& m_vector;
public:
    explicit AddChildren(vector>& theVector)
        : m_vector(theVector) {}

    template
    AddChildren& add(Arg1&& arg1, Arg2&& arg2)
    {
        m_vector.push_back(unique_ptr(
            new Child(std::forward(arg1), std::forward(arg2))));
        return *this;
    }
};

используемый следующим образом:

vector> myvector;
AddChildren(myvector)
    .add(var1, var2)
    .add(var3, var4)
    .add(var5, var6);

При использовании метод во время выполнения выбора типа, можно использовать оператора() и имеют его, похожи на это:

vector> myvector;
AddChildren(myvector)
    (childAType, var1, var2)(childBType, var3, var4)(childCType, var5, var6);

(Это может также быть сделано с выбором времени компиляции типа при помощи фиктивного объекта типа отборщика определенного типа для каждого детского типа в качестве параметра.)

Используя variadic шаблоны

Используйте variadic шаблон, чтобы снять с трех параметров за один раз и добавить дочерний объект.

void addChildren(vector>& theVector)
{}

template
void addChildren(vector>& theVector,
    FirstChild childtype, FirstArg1&& arg1, FirstArg2&& arg2, Rest&&... rest)
{
    addChild(theVector, childtype,
        std::forward(arg1), std::forward(arg2));
    addChildren(theVector, std::forward(rest)...);
}

template
vector> CreateVec(Args&&... args)
{
    vector> result;
    addChildren(result, std::forward(args)...);
    return result;

}

Я принимаю здесь существование функции addChild , который может добавить ребенка, учитывая его тип (в качестве параметра) и его аргументы.

Основная проблема с этим состоит в том, что у VS2012 нет variadic шаблонов. Есть два способа моделировать variadic шаблоны. 1. Напишите единственную функцию, которая берет максимальное количество параметров, в которых вы, возможно, нуждались бы, и дефолты большинство из них к некоторому известному типу, который можно взять, чтобы означать "не существующий". 2. Выпишите столько перегрузок, сколько вы думаете, что вам будет нужно.

Если вы знаете, что вам никогда не будут нужны больше, чем говорят десять дочерних объектов, второй вариант на самом деле совершенно выполним - только необходимо написать им однажды, и это - вероятно, меньше чем 150 линий кода. Альтернативно можно использовать Повышение. Препроцессор, чтобы произвести функции, но это - совершенно новый уровень сложности.

4
добавлено
С обновлением компилятора в ноябре 2012, ПРОТИВ 2012 делает , имеют variadic шаблоны.
добавлено автор Angew, источник
Как глубоко кроличья нора идет. Большой ответ!
добавлено автор qballer, источник

С обновлением компилятора в ноябре 2012, ПРОТИВ 2012 поддержек variadic шаблоны, таким образом, следующее должно работать (это - не совсем синтаксис, который вы после, но я думаю, что это достаточно близко):

struct VectorCreator
{
  explicit VectorCreator(std::vector &vec)
    : vec_(vec)
  {}

  template 
  VectorCreator& create(ArgType&&... arg)
  {
    vec_.push_back(std::unique_ptr(new Type(std::forward(arg)...));
    return *this;
  }

private:
  std::vector &vec_;
};

Используйте как это:

std::vector vec;
VectorCreator(vec).create(var1, var2).create(var3, var4).create(var5, var6);
2
добавлено
@ymett I don' t думают так. Если аргумент первоначально стал sometype& , вы хотите отправить его как sometype& . Обратите внимание что тип возвращения станд.:: отправьте </ код> T&& .
добавлено автор Angew, источник
You' право ре, но как оказалось, станд.:: отправьте имеет точно тот же самый эффект ( T& && -> T& ).
добавлено автор ymett, источник
Я думаю, что это должно быть станд.:: отправьте .
добавлено автор ymett, источник

С обновлением компилятора в ноябре 2012, ПРОТИВ 2012 поддержек variadic шаблоны, таким образом, следующее должно работать (это - не совсем синтаксис, который вы после, но я думаю, что это достаточно близко):

struct VectorCreator
{
  explicit VectorCreator(std::vector &vec)
    : vec_(vec)
  {}

  template 
  VectorCreator& create(ArgType&&... arg)
  {
    vec_.push_back(std::unique_ptr(new Type(std::forward(arg)...));
    return *this;
  }

private:
  std::vector &vec_;
};

Используйте как это:

std::vector vec;
VectorCreator(vec).create(var1, var2).create(var3, var4).create(var5, var6);
2
добавлено
@ymett I don' t думают так. Если аргумент первоначально стал sometype& , вы хотите отправить его как sometype& . Обратите внимание что тип возвращения станд.:: отправьте </ код> T&& .
добавлено автор Angew, источник
You' право ре, но как оказалось, станд.:: отправьте имеет точно тот же самый эффект ( T& && -> T& ).
добавлено автор ymett, источник
Я думаю, что это должно быть станд.:: отправьте .
добавлено автор ymett, источник
pro.cxx
pro.cxx
3 049 участник(ов)

C/C++ chat 0. Простые вопросы, лабы и о IDE — в чат новичков @supapro 1. Не хамим, не переходим на личности, не вбрасываем утверждения без доказательств 2. No Ads, offtop, flood Объявления о вакансиях и евенты - в лс @AlexFails https://t.me/ProCxx/259155

supapro.cxx
supapro.cxx
1 925 участник(ов)

Чат для тех, кто немного знает C++, простые вопросы по реализации, синтаксису и ide – сюда, а для другого есть: /Главный чат по серьезным вопросам — @ProCxx /Чат по обсуждению всего — @fludpac

C++ Russia
C++ Russia
384 участник(ов)

Сообщество разработчиков C++ в Telegram.

cxx.Дискуссионная
cxx.Дискуссионная
298 участник(ов)

это не двач, общайтесь вежливо; разговор на почти любые темы; Не согласны с баном? В лс @AlexFails, @ivario

C++ для маленьких и тупых
C++ для маленьких и тупых
105 участник(ов)

Лоу левел (по среднему IQ участников) чатик ExtremeCode @extremecode Флудилка @extremecode_rest