Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 递归模板-常量n大小数组->;n-1尺寸合适吗?_C++_Arrays_Templates - Fatal编程技术网

C++ 递归模板-常量n大小数组->;n-1尺寸合适吗?

C++ 递归模板-常量n大小数组->;n-1尺寸合适吗?,c++,arrays,templates,C++,Arrays,Templates,这可能是一个奇怪的问题,但我有一个递归模板,它需要一个大小为d的数组(其中d是一个模板参数),我希望将相同的数组传递给d-1模板,就像它短了一个元素一样。这样,我只使用一个数组,而不是为每个级别创建一个新数组 我觉得答案可能是一些非常基本的东西,但我找不出任何搜索词,导致任何接近我所寻找的东西 要将其放到上下文中,下面是一个示例 template<int d> void Function(int array[d]) { array[d- 1]= d; Function<

这可能是一个奇怪的问题,但我有一个递归模板,它需要一个大小为d的数组(其中d是一个模板参数),我希望将相同的数组传递给d-1模板,就像它短了一个元素一样。这样,我只使用一个数组,而不是为每个级别创建一个新数组

我觉得答案可能是一些非常基本的东西,但我找不出任何搜索词,导致任何接近我所寻找的东西

要将其放到上下文中,下面是一个示例

template<int d>
void Function(int array[d])
{
  array[d- 1]= d;
  Function<d- 1>(?);
}
模板
void函数(int数组[d])
{
数组[d-1]=d;
函数(?);
}

希望我能正确解释这一点,但是,当您将数组作为模板传递时,我假设您传递了一个数组大小的参数。(否则你怎么知道数组有多大?)当你传递数组时,你传递的是一个指向数组第一个元素的指针,所以当你传递子数组时,你可以传递一个指向下一个元素和大小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;
}
模板
T foo(T*ptr,整数大小){
如果(大小>0)
return*ptr+foo(ptr+sizeof(T),size-1);
其他的
返回0;
}

此答案适用于静态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';
}
#包括
//以部分专门化结束递归
模板
结构静态ArrayDump{
静态无效函数(T&a)[计数]){
使用较短的t=t(&)[count-1];
StaticArrayDump::func(重新解释强制转换(a));

std::cout根据您提供的信息,我假设您也想知道如何“停止”递归。这看起来像这样:

// 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...
}
//这是将从用户处调用的函数,如果我们可以轻松地进行此操作,则必须手动传递整型常量,这将是一种糟糕的设计
模板
内联
虚函数(int(&_数组)[I])
{
函数(_数组,标准::积分_常数);
}
//函数将递归地对其每个元素的数组执行某些操作
模板
空函数(int(&_数组)[I],标准::积分常数)
{
//做点什么。。。
函数(_数组,标准::积分_常数);
}
//功能与以前一样,只需进行一些修改
模板
空函数(int(&_数组)[I],标准::积分常数)
{
//做点什么。。。
//退出功能。。。
}

问题到底是什么?你能提供递归模板源吗?应该放在一个例子中!我刚刚添加了一个。数组的大小是常量;大小是一个模板参数。如果是这种情况,我不认为你想要什么是可能的,模板参数必须是静态的,因为函数是用模板t构造的在编译时而不是运行时键入。如果参数是一个常量和另一个常量的结果,则该参数仍然是常量。例如d-1(其中d是模板参数)。为什么要使用模板参数执行此操作?将d作为函数参数传递而不是作为模板参数传递不是更容易吗?我正在尝试看看是否可以利用阵列非常小的事实来提高性能(这是一个很好的答案!我不敢相信我没有想到重新解释强制转换-我想我不确定使用恒定大小的数组时是如何工作的,我不认为只是强制强制转换。你的其余答案也很有帮助,因为(如你所示)在实现这个特殊的递归过程中还有其他一些困难。我已经解决了结构的部分专门化,但是我不知道你发布的第二个方法。谢谢!重载版本在类型_select中利用了类专门化,因此在技术上也是基于专门化的,但我认为真正的基于重载的技术仍然是可能的。重新解释_cast让我担心,但只要通过访问每个元素(而不是作为一个整体单元)访问数组,就不应该违反严格的别名ke可以通过将其嵌入到结构中来实现。我又添加了两种技术。最后一种是目前为止最好的,也是结束递归的唯一方法。LolI实际上只是好奇如何在不创建新数组的情况下获取T[d]的输入并使其成为T[d-1]。