如何在 C++ 中创建自定义整数序列
How to create custom integer sequence in 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)...);
}
我想将任何变量序列传递给 bar,以便此序列转换为 '1, value1, 2, value2, 3、value3'。所以每个值都遵循其基本序列中的数字。但是我无法创建这个 'magic code' 来在这两个状态之间转换编译阶段的序列。
这是一个 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
我认为您可以接受较小的性能影响.
不是很优雅,但是,使用元组,std::tie
,等等...
以下示例应该适用于 C++11
--- 编辑 ---
修改和统一(C++11 没有 C++14 元素)我的第一个例子。
不需要std::index_sequence
(可以用一个普通的struct indSeq
代替)或std::make_index_sequence
(索引序列可以使用sizeof...(I)
逐步构造);不再需要 qux()
。
#include <tuple>
#include <iostream>
void foo ()
{ }
template <typename T0, typename ... Types>
void foo (const T0 & v0, const Types & ... values)
{
std::cout << "-- " << v0 << std::endl;
foo(values...);
}
template <std::size_t ...>
struct indSeq
{ };
template <std::size_t ... Is, typename ... Ts1>
void baz (std::size_t, const indSeq<Is...> &, const std::tuple<Ts1...> & t)
{ foo(std::get<Is>(t)...); }
template <std::size_t ... Is, typename ... Ts1, typename T0, typename ... Ts2>
void baz (std::size_t n, const indSeq<Is...> &, const std::tuple<Ts1...> & t,
const T0 & v0, const Ts2 & ... vs)
{ baz(n+1U, indSeq<Is..., sizeof...(Is), sizeof...(Is)+1U>(),
std::tuple_cat(t, std::tie(n), std::tie(v0)), vs...); }
template <typename ... Types>
void bar (const Types & ... values)
{ baz (1U, indSeq<>(), std::tuple<>(), values...); }
int main()
{
bar(11, 22L, "33", 44.44);
return 0;
}
p.s.: 抱歉我的英语不好。
我有这样的功能:
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)...);
}
我想将任何变量序列传递给 bar,以便此序列转换为 '1, value1, 2, value2, 3、value3'。所以每个值都遵循其基本序列中的数字。但是我无法创建这个 'magic code' 来在这两个状态之间转换编译阶段的序列。
这是一个 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
我认为您可以接受较小的性能影响.
不是很优雅,但是,使用元组,std::tie
,等等...
以下示例应该适用于 C++11
--- 编辑 ---
修改和统一(C++11 没有 C++14 元素)我的第一个例子。
不需要std::index_sequence
(可以用一个普通的struct indSeq
代替)或std::make_index_sequence
(索引序列可以使用sizeof...(I)
逐步构造);不再需要 qux()
。
#include <tuple>
#include <iostream>
void foo ()
{ }
template <typename T0, typename ... Types>
void foo (const T0 & v0, const Types & ... values)
{
std::cout << "-- " << v0 << std::endl;
foo(values...);
}
template <std::size_t ...>
struct indSeq
{ };
template <std::size_t ... Is, typename ... Ts1>
void baz (std::size_t, const indSeq<Is...> &, const std::tuple<Ts1...> & t)
{ foo(std::get<Is>(t)...); }
template <std::size_t ... Is, typename ... Ts1, typename T0, typename ... Ts2>
void baz (std::size_t n, const indSeq<Is...> &, const std::tuple<Ts1...> & t,
const T0 & v0, const Ts2 & ... vs)
{ baz(n+1U, indSeq<Is..., sizeof...(Is), sizeof...(Is)+1U>(),
std::tuple_cat(t, std::tie(n), std::tie(v0)), vs...); }
template <typename ... Types>
void bar (const Types & ... values)
{ baz (1U, indSeq<>(), std::tuple<>(), values...); }
int main()
{
bar(11, 22L, "33", 44.44);
return 0;
}
p.s.: 抱歉我的英语不好。