向具有可变模板的函数传递对数组的可变引用数

Passing a variable number of references-to-arrays to a function with variadic templates

本文关键字:数组 引用 函数      更新时间:2023-10-16

我知道如何编写一个接受可变数量参数的可变模板函数:

template<int I, typename... Rest>
void f() {
    // whatever
}

我知道如何编写一个模板函数来接受对数组的引用:

template<typename T, unsigned int Length>
void f(T(&arr)[Length]) {
    // whatever
}

但我想不出如何将两者结合起来,使函数接受对数组的可变数量的引用。

我的第一次尝试是

template<typename T, unsigned int Length>
unsigned int arrlen(T(&)[Length]) {
    return Length;
}
template<typename T, unsigned int Length>
int f(T(&arr)[Length]) {
    return Length;
}
template<typename T, unsigned int Length, typename... Rest>
int f(T(&arr)[Length], Rest... rest) {
    return Length + f(rest...);
}
int main() {
    int a[] = {1 , 2, 3}, b[] = {1, 2, 3, 4, 5}, c[] = {1};
    cout << f(a, b, c);
}

但编译器告诉我

a.cpp:在函数'int f(T(&)[Length]中,Rest…)[其中T=int,unsigned int Length=3u,Rest={int*,int*}]'

a.cpp:23:22:从这里实例化

a.cpp:17:27:错误:没有用于调用"f(int*&,int*&aamp;)"的匹配函数

a.cpp:17:27:注:候选人为:

a.cpp:11:22:注意:模板int f(T(&)[Length])

a.cpp:16:5:注意:模板int f(T(&)[Length],Rest…)

所以我在想,你可以写一个对象来存储构造它的数组的长度,然后将其中的一个变量(它将从传递的数组中隐式构造)传递给函数。这是我的尝试:

template<typename T, unsigned int Length>
struct Array {
    Array(T(&arr)[Length]) : arr(arr), len(Length) { }
    T(&arr)[Length];
    const unsigned int len;
};
int f() {
    return 0;
}
template<typename T, unsigned int Length, typename... Args>
int f(const Array<T, Length>& a1, Args... rest) {
    return a1.len + f(rest...);
}
int main() {
    int a[] = { 1, 2, 3 }, b[] = { 1, 2, 3, 4, 5 }, c[] = { 1 };
    cout << f(a, b, c);
}

但当我试图用GCC 4.6.1编译它时,我得到了错误

a.cpp:在函数"int main()"中:

a.cpp:27:22:错误:没有用于调用"f(int[3],int[5],int[1])"的匹配函数

a.cpp:27:22:注:候选人为:

a.cpp:16:47:注意:模板int f(const Array&,Args…)

a.cpp:20:5:注:int f()

a.cpp:20:5:注意:候选人期望0个参数,提供3个

然而,除了修复第二个代码(这更像是一种解决方法,因为我不知道如何做我真正想做的事情),这个问题的实际意义和我真正想学习的东西是如何在不使用代理对象的情况下做到这一点,如果可能的话,就像第一个代码一样。那么如何做到这一点呢?在我发布的一个尝试中,是否只是一个简单的语法错误?

如果你只想求出一些数组的长度,你可以直接这样做:

template<typename T, unsigned int Length>
int f(const T (&)[Length]) {
    return Length;
}
template<typename T, unsigned int Length, typename... Args>
int f(const T (&)[Length], Args&... rest) {
    return Length + f(rest...);
}
int main() {
    int a[] = { 1, 2, 3 }, b[] = { 1, 2, 3, 4, 5 }, c[] = { 1 };
    std::cout << f(a, b, c);
}

您可以使用std::extent来获取数组外部维度的范围,并对这些范围进行方差求和:

#include <type_trait>
template <typename Arr, typename ...Rest> struct extent_sum
: std::integral_constant<std::size_t,
                         std::extent<T>::value + extent_sum<Rest...>::value> { };
template <typename T> struct extent_sum<T>
: std::integral_constant<std::size_t, std::extent<T>::value> { };

用法:

const std::size_t n = extent_sum<int[2], char[4], float[3], bool>::value;