【问题标题】:Passing a variable number of references-to-arrays to a function with variadic templates将可变数量的数组引用传递给具有可变参数模板的函数
【发布时间】:2012-02-10 17:55:31
【问题描述】:

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

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

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

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

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 个

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

【问题讨论】:

  • 只需使用 std::array 并忘记原始数组的废话。
  • @CatPlusPlus 这将是一个简单的方法,不会帮助我了解这里发生了什么。
  • @CatPlusPlus 实际上会出现同样的问题
  • 不,不会。 std::array 不会衰减为指针,因此您不必使用作为模板参数传递的大小。
  • @CatPlusPlus 啊你是对的,我忘了问题是由数组到指针衰减引起的

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


【解决方案1】:

如果你只是想把多个数组的长度相加,你可以直接这样做:

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

【讨论】:

  • 所以我唯一缺少的就是Args前面的&amp;
  • @SethCarnegie:肯定在后面吗?
  • @LightnessRacesinOrbit 取决于单词朝向的方向 :)
  • 啊,那是愚蠢的错误。 Args&amp;是不是表示所有参数都是引用传递,Args是表示所有都是值传递?
  • @Seth : 是的,但是Args&amp;&amp; 确实在每个参数的基础上引用折叠,所以如果你想同时支持右值和左值(这里不是必需的),在一般情况下它是首选。
【解决方案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;

【讨论】:

猜你喜欢
  • 2014-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-15
  • 1970-01-01
  • 1970-01-01
  • 2011-03-16
  • 1970-01-01
相关资源
最近更新 更多