Как я могу преобразовать каждый параметр в шаблоне переменной функции в другой тип и получить его адрес?

#c

#c

Вопрос:

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

 void Bar(std::initializer_list<Base*> objects);
 

Теперь я хочу создать шаблон функции, который обертывает каждый параметр в тип, производный от Base и передает их функции выше. Что-то вроде:

 template <class... Params> void Foo(Params... parameters)
{
    Bar({amp;Wrapper<Params>(parameters)...});
}
 

(Класс Wrapper специализирован для различных типов.) Этот код фактически компилируется в MSVC, но компилятор выдает предупреждение, потому что я беру адрес rvalue (который запрещен стандартом). Есть ли простой, соответствующий стандартам способ добиться того же? (Я думаю, что я могу сделать это с помощью tuples, integer_sequences и вспомогательной функции, но я бы хотел избежать этого, если это возможно.)

Комментарии:

1. Создайте tuple<Wrapper<Params>...> , а затем возьмите адреса элементов кортежа?

2. Кортеж, безусловно, помогает мне в этом, но есть ли способ получить адрес каждого элемента кортежа, не проходя через integer_sequence?

3. Вместо списка указателей инициализатора вы можете использовать список ссылок инициализатора rvalue?

4. Я в это не верю. Массивы ссылок являются незаконными.

Ответ №1:

Проблема Wrapper<T> в том, что экземпляры должны существовать по некоторому адресу. Самый простой способ сделать это — создать std::tuple<Wrapper<Params>...> экземпляр. Раздражает то, что вам приходится извлекать содержимое обратно с помощью std::get<N> . В C 14 std::index_sequence существует, чтобы помочь вам в этом вопросе.

 template <class... Params, std::size_t... Idx>
void FooImpl(std::tuple<Wrapper<Params>...>amp; tup, std::index_sequence<Idx...>)
{
    Bar({ (amp;std::get<Idx>(tup))... });
}

template <class... Params>
void Foo(Params... parameters)
{
    std::tuple<Wrapper<Params>...> tup(Wrapper<Params>(parameters)...);
    FooImpl(tup, std::make_index_sequence<sizeof...(Params)>());
}
 

Если вы Bar используете const Wrapper<T>* s, другим вариантом является использование правил C constant ref в ваших интересах.

 template <class... Params>
void FooImpl(const Wrapper<Params>amp;... parameters)
{
    Bar({ (amp;parameters)... });
}

template <class... Params>
void Foo(Params... parameters)
{
    FooImpl(Wrapper<Params>(parameters)...);
}
 

Комментарии:

1. Как это бывает, Bar может принимать оболочку const . Это работает довольно хорошо. Хотя, по правде говоря, решение integer_sequence не так уж плохо, теперь, когда я его вижу. Спасибо за вашу помощь.