Пересылка нескольких наборов переменных аргументовC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Пересылка нескольких наборов переменных аргументов

Сообщение Anonymous »

Я создаю контейнер, который использует в качестве внутреннего представления пару стандартных контейнеров, каждый из которых имеет свой тип. Мне нужно написать свою версию emplace(..), и вот тут я застрял.
Это то, к чему сводится мой код, с функцией emplace, которая не компилируется, но, надеюсь, поможет вам понять, чего я пытаюсь достичь:

Код: Выделить всё

template 
class MyContainer
{
public:
template 
void emplace(ArgsA&&... argsA, ArgsB&&... argsB)
{
// do custom logic
a_container.emplace_back(std::forward(argsA)...);
b_container.emplace_back(std::forward(argsB)...);
}

private:
std::vector a_container;
std::vector b_container;
};
Как я уже сказал, это явно не работает, поскольку компилятор не может волшебным образом решить, где прекратить чтение первого пакета аргументов и начать второй. Когда я вижу проблемы такого рода, мой опыт метапрограммирования заставляет меня немедленно обратиться к std::tuple. Если есть лучшее решение, пожалуйста, подпишитесь, но с этого момента я буду считать, что это самый простой способ двигаться вперед.
Итак, используя std::tuple, проблему можно разложить на несколько разных шагов. На каждом этапе мне необходимо обеспечить сохранение характера аргументов (r-значение или l-значение):
  • передать аргументы для размещения в кортеже
  • прочитать кортеж из моей функции emplace
  • распаковать кортеж
  • передать распакованные элементы кортежа в emplace_back(..)
Что касается пункта 1., хотя у вызывающего объекта уже может быть под рукой std::tuple, в большинстве случаев он, вероятно, будет вызывать emplace, используя непосредственно параметры, которые он хочет в конечном итоге передать двум конструкторам. Кажется, это именно то, для чего был создан std::forward_as_tuple, если я не ошибаюсь. Если да, то я бы считал это выполненным.
Пункт 2. доставляет небольшое неудобство. То есть переписывание emplace для приема std::tuple:

Код: Выделить всё

template 
void emplace(std::tuple tupleA, std::tuple tupleB)
К сожалению, эти переменные ArgsA и ArgsB не могут пересылать ссылки, поскольку они не выводятся напрямую из природы tupleA и tupleB, а из их типов. Поэтому мне придется помнить, что это могут быть ссылки как на r-значение, так и на l-значение, и очищать их при пересылке.
Более того, я думаю, что способ передачи std::tuple может привести к странному поведению. Выше я написал «ленивую версию», которая принимает std::tuple путем копирования, но в большинстве случаев, когда я пишу контейнер, я предпочитаю, как и стандарт, использовать как версию const std::tuple&, так и версию std::tuple&& для максимальной гибкости. В этом случае версия const std::tuple& будет иметь std::get для извлечения только версии наших аргументов с l-значениями из-за правил свертывания ссылок, что противоречит сути. Поэтому я подумываю о написании только std::tuple&& и (возможно) о сохранении копии.
Пункты 3. и 4. являются самыми трудными. Я считаю, что мне придется решать их вместе, и я очень удивлен, что стандарт, насколько я понимаю, предлагает std::forward_as_tuple, но не обратную операцию. Здесь есть тонкая проблема, которая не позволяет использовать простое решение пересылки с использованием такого кода:

Код: Выделить всё

template 
void emplace(std::tuple tupleA, std::tuple tupleB)
{
// do custom logic
a_container.emplace_back(std::forward(std::get(tupleA))...);
...
Это совершенно не работает, если в std::tuple повторяются типы. Поэтому нам нужно использовать индексный доступ, и моя лучшая идея на данный момент — написать оболочку std::invoke, которая будет использовать std::integer_sequence для распаковки std::tuple, но это всего лишь интуиция, и мне нужно проработать детали. Как было сказано и показано выше, во всем этом хаосе мне все равно придется не забывать удалять ссылки из типов, из которых состоит std::tuple, чтобы уточнить соответствующие аргументы.
Я особенно ищу более простые решения для пунктов 3. и 4.

Подробнее здесь: https://stackoverflow.com/questions/797 ... -arguments
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»