Как создать пользовательскую целочисленную последовательность в C++
у меня есть такая функция:
template <typename ... Types>
void foo(const Types & ... values)
{
// expected that 'values' is sequence like
// '1, customvalue1, 2, customvalue2, 3,...'
}
и вторая функция:
template <typename ... Types>
void bar(const Types & ... values)
{
// where 'values' are any variables
// some magic here
foo((int_seq<sizeof...(Types)>, values)...);
}
Я хотел бы передать любую последовательность переменных в бар, так что эта последовательность преобразуется в последовательность, как '1, value1, 2, value2, 3, value3'. Таким образом, каждое значение следует своему номеру в базовой последовательности. Но я не могу создать это 'волшебный код' для преобразования последовательности на этапе компиляции между этими двумя состояниями.
2 ответов
не очень элегантный, но, используя кортежи,std::tie
, etc...
следующий пример должен работать с C++11
--- редактировать ---
Modified and unified (C++11 без элементов C++14) мой первый пример.
Не нужно std::index_sequence
(тривиальное struct indSeq
можно использовать вместо) или std::make_index_sequence
(последовательность индексов может быть построена шаг за шагом с помощью sizeof...(I)
); не нужно
вот решение C++14, но все необходимые части библиотеки также могут быть написаны на C++11.
#include <iostream>
#include <tuple>
#include <utility>
template <typename ... Types>
void foo(const Types & ... values)
{
using swallow = bool[];
(void)swallow{ (std::cout << values << std::endl,false)... };
}
template <std::size_t N, bool = (N%2==0)>
struct pick {
template<typename... Types>
static std::size_t get(const std::tuple<Types...>&) { return N/2; }
};
template <std::size_t N>
struct pick<N,false> {
template<typename... Types>
static auto get(const std::tuple<Types...>& t) { return std::get<N/2>(t); }
};
template <std::size_t... Indices, typename ... Types>
void bar2(const std::index_sequence<Indices...>, const Types & ... values)
{
auto x = std::tie(values...);
foo(pick<Indices>::get(x)...);
}
template <typename ... Types>
void bar(const Types & ... values)
{
bar2(std::index_sequence_for<Types...,Types...>(), values...);
}
int main()
{
bar( "Hallo", 42, 1.23 );
}
в настоящее время он основан на нуле, но +1
в нужном месте это легко исправить. Кроме того, он создает промежуточное std::tuple
со ссылками на значения, если производительность является проблемой, могут существовать лучшие варианты, но так как вы не использовали std::forward
Я подумал, что небольшое влияние на производительность может быть приемлемый для вас.