将可变数量的引用到数组传递给具有可变参数模板的函数

时间:2012-02-10 17:55:32

标签: c++ templates c++11 variadic-templates

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

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(&amp;)[Length],Rest ...)[with T = int,unsigned int Length = 3u,Rest = {int *,int *}]'

     

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

     

a.cpp:17:27:错误:没有匹配函数来调用'f(int *&amp;,int *&amp;)'

     

a.cpp:17:27:注意:候选人是:

     

a.cpp:11:22:注意:模板int f(T(&amp;)[长度])

     

a.cpp:16:5:注意:模板int f(T(&amp;)[长度],休息......)

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

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:注意:template int f(const Array&amp;,Args ...)

     

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

     

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

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

2 个答案:

答案 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);
}

答案 1 :(得分:2)

您可以使用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;