这可能是一个奇怪的问题,但我有一个递归模板,需要一个大小为d的数组(其中d是模板参数),我想将d-1模板传递给相同的数组,就好像它是一个元素更短。这样我只使用一个数组,而不是为每个级别创建一个新数组。
我觉得答案可能是非常基本的,但我无法提出任何与我正在寻找的内容相近的搜索字词。
将此置于上下文中,这是一个例子
template<int d>
void Function(int array[d])
{
array[d- 1]= d;
Function<d- 1>(?);
}
答案 0 :(得分:1)
这个答案适用于静态的C风格数组,如果您的问题是关于std :: Array,我道歉。
在我的脑海中,我提出了两种方法来进行递归,但还有更多的技术。
第一个使用部分专用的类(数组计数为零)来终止递归。
第二种方法使用强制转换为静态选择的类型,它使用重载函数结束递归。在这里,我将数组转换为void *,但是对于不能使用它的类型,您可以创建一个可以从原始类型构造的自定义类型。
我使用reinterpret_cast将数组的类型从数组[count]的引用更改为数组[count-1]。虽然我希望这在这里使用是安全的,但请记住,在不同的情况下你可能会遇到问题。
#include <iostream>
// Ends recursion with a partial specialization
template <typename T, int count>
struct StaticArrayDump {
static void func(T(&a)[count]) {
using shorter_t = T(&)[count-1];
StaticArrayDump<T, count-1>::func(reinterpret_cast<shorter_t>(a));
std::cout << a[count-1] << ' ';
}
};
template <typename T>
struct StaticArrayDump<T,0> {
static void func(...) {}
};
template <typename T, int count>
static void static_array_dump_spec(T(&a)[count]) {
using shorter_t = T(&)[count-1];
StaticArrayDump<T,count>::func(a);
}
// Ends recursion with void* cast and function overload
// Ultimately relies on type_select's specialization, however
template <bool, typename A, typename B> struct type_select /* true */ { using type = A; };
template <typename A, typename B> struct type_select<false,A,B> { using type = B; };
template <bool cond, typename A, typename B>
using type_select_t = typename type_select<cond, A, B>::type;
static void static_array_dump_ovld(...) {}
template <typename T, int count>
static void static_array_dump_ovld(T(&a)[count]) {
static const int next_count = count-1;
using shorter_t = T(&)[next_count];
static_array_dump_ovld(reinterpret_cast<
type_select_t<next_count!=0, shorter_t, void*>
>(a));
// output the last element
std::cout << a[count-1] << ' ';
}
// This is an overload-based version which is free of
// any reliance on template specialization.
// helper_trueol's (void*, void*) overload will only be
// selected for arguments (array_ref, count) when count
// is 0, because 0 is the only integer which can be
// converted to a pointer.
// This one's compiler compatibility is a bit shaky...
// MSVC 2013 OK
// IdeOne g++ needs int cast for next_count
static void helper_trueol(void*, void*) {}
template <typename T, int count>
static void helper_trueol(T(&a)[count], int) {
static const int next_count = count-1;
using shorter_t = T(&)[next_count];
helper_trueol(reinterpret_cast<shorter_t>(a), int(next_count));
std::cout << a[count-1] << ' ';
}
template <typename T, int count>
static void static_array_dump_trueol(T(&a)[count]) {
helper_trueol(a, count);
}
// Finally, this overload-based version relies
// on SFINAE to disqualify the template function
// as a candidate when count is 0 because the
// zero-length array type triggeres a substitution
// failure.
// So just using this template array argument type,
// the same one used in all of the previous examples,
// but without any extra mechanisms, is all you need
// to end this recursion!
// This is the obvious best way, of course.
static void static_array_dump_sfinae(...) {}
template <typename T, int count>
static void static_array_dump_sfinae(T(&a)[count]) {
static const int next_count = count-1;
using shorter_t = T(&)[next_count];
static_array_dump_sfinae(reinterpret_cast<shorter_t>(a));
std::cout << a[count-1] << ' ';
}
//////
int main() {
double dbl_array[] = { 0, 1.2, 3.4, 5.6789, 10 };
static_array_dump_spec(dbl_array);
std::cout << '\n';
const char* cstr_array[] = { "zero", "one", "two", "three", "four" };
static_array_dump_ovld(cstr_array);
std::cout << '\n';
char charray[] = "Hello";
charray[sizeof(charray)-1] = '!'; // replace nul terminator
static_array_dump_trueol(charray);
std::cout << '\n';
bool barray[] = {true, true, true, false, true, false, false, false};
std::cout << std::boolalpha;
static_array_dump_sfinae(barray);
std::cout << '\n';
}
答案 1 :(得分:0)
希望我正确地解释这一点,但是,当您将数组作为模板传递时,我假设您传递了一个数组大小的参数。 (否则你怎么知道数组的大小?)当你传递数组时,你传递的指针指向数组的第一个元素,所以当你传递子数组时,你只需要将指针传递给下一个元素, size d-1或指向下一个元素和大小d-1的迭代器。
示例:
template< typename T>
T foo(T * ptr, int size) {
if (size > 0)
return *ptr + foo(ptr + sizeof(T), size - 1);
else
return 0;
}
答案 2 :(得分:0)
根据您提供的信息,我假设您也想知道如何“停止&#34;递归。这看起来像这样:
// this is the function that will be called from the user, it would be bad design too have to pass an integral constant manually when we can easily do this
template <std::size_t I>
inline
void Function(int (&_array)[I])
{
Function(_array, std::integral_constant<std::size_t, I>);
}
// function will recursively do something with an array for each of it's elements
template<std::size_t I>
void Function(int (&_array)[I], std::integral_constant<std::size_t, I>)
{
// do something...
Function(_array,std::integral_constant<std::size_t,I-1>);
}
// function as before with a few modifications
template<std::size_t I>
void Function(int (&_array)[I], std::integral_constant<std::size_t, 1>)
{
// do something...
// exit function...
}