c++ - 递归模板 - 常量 n 大小数组 -> n-1 大小就地?

标签 c++ arrays templates

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

我觉得答案可能是一些非常基本的东西,但我无法想出任何搜索词来得出与我正在寻找的东西接近的结果。

为了说明这一点,这里有一个例子

template<int d>
void Function(int array[d])
{
  array[d- 1]= d;
  Function<d- 1>(?);
}

最佳答案

此答案适用于静态的 C 风格数组,如果您的问题是关于 std::Array,我深表歉意。

在我的脑海中,我想出了两种方法来进行递归,但还有更多的技术存在。

第一个使用部分特化类(数组计数为零)来终止递归。

第二种方法使用静态选择类型的转换,以重载函数结束递归。在这里,我将数组转换为 void*,但对于不适用于此的类型,您可以创建一个可从原始类型构造的自定义类型。

我求助于使用 reinterpret_cast 将数组的类型从对 array[count] 的引用更改为 array[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';
}

关于c++ - 递归模板 - 常量 n 大小数组 -> n-1 大小就地?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36464121/

相关文章:

java - 当我从Java代码执行C++时未显示任何输出

c++ - 编译器无法识别模板化的类

php - 在第二个循环中重用第一个循环中的引用变量会损坏我的数组数据

c++ - C++ 模板的优缺点是什么?

c++ - 合并指针

c++ - 类型特征以检查参数包中的所有类型是否都是可复制构造的

c - 在我的 C 程序中,为什么我的跟踪循环和实际输出不同?

javascript - 比较两个包含对象的数组,包括其他对象、数组等

c++ - 使用枚举成员模板化成员函数

c++ - 如何检测类型是否具有运算符 << 重载?