Bry*_*yce 7 c++ templates variadic-templates c++11
我的目标是做一些事情,例如,
pairs<1,2,3,4>()
Run Code Online (Sandbox Code Playgroud)
有退货类型
std::tuple<some_other_type<1,2>, some_other_type<2,3>, some_other_type<3,4>>
Run Code Online (Sandbox Code Playgroud)
我想知道这是否可能与C++模板元编程,以及如何实现它.为了实际生成该值,似乎我可以使用tuple_cat递归地连接到输出,但我发现很难表达返回类型,因为它本身是可变参数并且实际上是模板参数数量的函数.使情况复杂化,如果我去了tuple_cat路由,似乎我也必须重载函数以使元组连接到,并且连接将在运行时发生,而不是编译时.我在野鹅追逐吗?
And*_*owl 12
这是一种方法.鉴于您的课程模板some_other_type:
template<int I, int J>
struct some_other_type { };
Run Code Online (Sandbox Code Playgroud)
并且在detail命名空间中隐藏了一些机制:
namespace detail
{
template<int... Is>
struct pairs { };
template<int I, int J>
struct pairs<I, J>
{
using type = std::tuple<some_other_type<I, J>>;
};
template<int I, int J, int... Is>
struct pairs<I, J, Is...>
{
using type = decltype(std::tuple_cat(
std::tuple<some_other_type<I, J>>(),
typename pairs<J, Is...>::type()));
};
}
Run Code Online (Sandbox Code Playgroud)
您可以提供一个实例化辅助类模板的简单函数:
template<int... Is>
typename detail::pairs<Is...>::type pairs()
{
return typename detail::pairs<Is...>::type();
}
Run Code Online (Sandbox Code Playgroud)
以下是您将如何使用它(以及测试用例):
#include <type_traits>
int main()
{
auto p = pairs<1, 2, 3, 4>();
// Won't fire!
static_assert(
std::is_same<
decltype(p),
std::tuple<
some_other_type<1,2>,
some_other_type<2,3>,
some_other_type<3,4>>
>::value,
"Error!");
}
Run Code Online (Sandbox Code Playgroud)
最后,这是一个实例.
改进:(为什么写<1, 2, 3, 4>一个人可以写<1, 5>)?
还可以扩展上述解决方案,以便不需要手动将最小值和最大值之间的每个数字写为模板参数pairs().鉴于下面的其他机制,再次隐藏在detail命名空间中:
namespace detail
{
template <int... Is>
struct index_list { };
template <int MIN, int N, int... Is>
struct range_builder;
template <int MIN, int... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};
template <int MIN, int N, int... Is>
struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
{ };
// Meta-function that returns a [MIN, MAX) index range
template<int MIN, int MAX>
using index_range = typename range_builder<MIN, MAX>::type;
template<int... Is>
auto pairs_range(index_list<Is...>) -> decltype(::pairs<Is...>())
{
return ::pairs<Is...>();
}
}
Run Code Online (Sandbox Code Playgroud)
它可以定义一个辅助函数pairs_range(),它接受2个模板参数定义的范围[begin, end)-在end不包括在标准库的风格:
template<int I, int J>
auto pairs_range() -> decltype(pairs_range(detail::index_range<I, J>()))
{
return pairs_range(detail::index_range<I, J>());
}
Run Code Online (Sandbox Code Playgroud)
这就是人们如何使用它(包括测试用例):
int main()
{
// Won't fire!
static_assert(
std::is_same<
decltype(pairs_range<1, 5>()),
decltype(pairs<1, 2, 3, 4>())
>::value,
"Error!");
}
Run Code Online (Sandbox Code Playgroud)
再一次,这是一个现实的例子.
这是我的版本(现场),100% 编译时,将新参数列表作为类型返回(而不是函数返回):
首先,让我们定义我们的结果结构:
template<int a, int b>
struct tpair
{
};
template<typename... p>
struct final_
{
};
Run Code Online (Sandbox Code Playgroud)
关键点是连接参数包。这是完成这项工作的结构:
template<typename a, typename b>
struct concat
{
};
template<typename a, typename... b>
struct concat<a, final<b...>>
{
typedef final_<a,b...> type;
};
Run Code Online (Sandbox Code Playgroud)
现在,该结构用于“配对”您的列表。通常它会因奇数个值而失败:
template<int a, int b, int... values>
struct pairize
{
// Choose one of the following versions:
// First version: only non-overlapping pairs : (1,2) (3,4) ...
typedef typename concat<tpair<a,b>, typename pairize<values...>::type>::type type;
// Second version: overlapping pairs : (1,2) (2,3) (3,4)...
typedef typename concat<tpair<a,b>, typename pairize<b,values...>::type>::type type;
};
template<int a, int b>
struct pairize<a,b>
{
typedef final_<tpair<a,b>> type;
};
Run Code Online (Sandbox Code Playgroud)
在实际示例中,还有一段代码将参数包中所有类型的名称输出到控制台,并进行分解,作为测试(比不完整的类型技巧使用起来更有趣)。