загрузка значений из пакета переменных аргумента во временный массив

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

error: cannot bind ‘std::string’ lvalue to ‘std::string&&’
error:   initializing argument 3 of ‘void pack_arg(datum*, size_t, std::string&&)’

и вызывается наличием вызова к shut_the_door, Если я достану && в соответствующей перегрузке pack_arg, затем компилируется, но сгенерированный код, по-видимому, копирует обе строки без необходимости. Во-вторых, мне нужно убедиться, что все временные строки, что массив d держит указатели, оставайся в живых до vprocess, Прямо сейчас сгенерированный код, кажется, разрушает их прямо перед этим вызовом.

Я готов рассмотреть довольно радикальные изменения в том, как массив заполняется, если у меня есть возможность запустить каждый аргумент process через перегруженный вызов функции, независимый от всех других подобных аргументов. (В частности, я подозреваю, что из-за специальных правил для временных инициализаций ссылки проблема 2 исчезнет, ​​если я смогу использовать std::string& в союзе, но как каждый член datum Массив заполняется присваиванием, а не инициализацией, что в настоящее время не будет работать, и я не знаю, как его заполнить инициализацией, не теряя при этом вызовы pack_arg, которые необходимы в более широком контексте.)

РЕДАКТИРОВАТЬ: С помощью std::forward между pack_args а также pack_arg не похоже на помощь; Я получаю точно такие же сообщения об ошибках.

#include <string>
#include <stddef.h>
using std::string;

union datum
{
const string* s;
int i;
};

inline void
pack_arg(datum* d, size_t n, int t)
{
d[n].i = t;
}

inline void
pack_arg(datum* d, size_t n, string && t)
{
d[n].s = &t;
}

inline void
pack_args(datum*, size_t)
{
}

template <typename X, typename... XS> inline void
pack_args(datum* d, ::size_t n, X&& x, XS&&... xs)
{
pack_arg(d, n, x);
pack_args(d, n+1, xs...);
}

extern void vprocess(datum*, size_t);

template <typename... XS> inline void
process(XS&&... xs)
{
size_t n = sizeof...(xs);
datum d[n];
pack_args(d, 0, xs...);
vprocess(d, n);
}

extern string shut_the_door();

void
demo()
{
process(1, 2, "buckle my shoe", 3, 4, shut_the_door());
}

0

Решение

Люк приносит действительно интересное замечание (я кратко просмотрел код, читая только подписи):

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

Чем больше я думаю о вашем коде, тем больше я верю, что все это просто плохая идея. Без тега о том, что представляет собой каждый элемент, вы не сможете узнать после того, какой элемент массива какого типа. Время жизни объектов будет трудно поддерживать (для std::stringв частности …) Может быть, вы должны переосмыслить дизайн в целом.


Вы столкнулись с интересной особенностью нового синтаксиса C ++ 11. Двойной амперсанд (&&) в этих двух декларациях на самом деле не одно и то же:

inline void
pack_arg(datum* d, size_t n, string && t);         // [1]
template <typename X, typename... XS> inline void
pack_args(datum* d, ::size_t n, X&& x, XS&&... xs) // [2]

В [1] аргумент типа string&& будет привязываться только к r-значению, позволяющему различать временный (или std::moved объект) из lvalue. Rvalue ссылка ведет себя как lvalue внутри функции. В [2], потому что вы находитесь в шаблоне и X является логическим типом, применяется другой набор правил и X&& будет преобразован либо в ссылку lvalue, либо в ссылку rvalue, в зависимости от аргумента.

В вашем случае аргумент на самом деле является временным, поэтому X&& будет сопоставлен с std::string&&, но внутри функции она рассматривается как lvalue и не может быть связана. Вы можете исправить это, добавив std::forward:

template <typename X, typename... XS> inline void
pack_args(datum* d, ::size_t n, X&& x, XS&&... xs)
{
pack_arg(d, n, std::forward(x));
pack_args(d, n+1, std::forward(xs)...);
}

std::forward Шаблон создаст ссылку lvalue или rvalue в зависимости от того, является ли аргумент самой ссылкой lvalue или rvalue.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]