Передача переменного числа ссылок на массивы в функцию с вариационными шаблонами - PullRequest
4 голосов
/ 10 февраля 2012

Я знаю, как написать функцию шаблона переменной, которая принимает переменное число аргументов:

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 (&) [Длина], Rest ...) [с T = int, без знака int Длина = 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 (&) [Длина])

a.cpp: 16: 5: примечание: шаблон int f (T (&) [Длина], остальные ...)

Итак, я былдумая, что вы могли бы написать объект, который будет хранить длину массива, с которым он был построен, а затемss переменное число тех (которые были бы неявно созданы из переданных массивов) в функцию.Вот моя попытка:

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: In function '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: note: int f ()

a.cpp: 20: 5: note: кандидат ожидает 0 аргументов, 3 предоставлено

Однако, кроме исправления второгокод (это скорее обходной путь для незнания того, как делать то, что я действительно хочу сделать), реальный смысл этого вопроса и то, что я на самом деле хотел бы узнать, как это сделать без использования прокси-объектов, подобных этому, если это возможновроде первый код.Так как это можно сделать?Была ли простая синтаксическая ошибка в одной из опубликованных мной попыток?

Ответы [ 2 ]

3 голосов
/ 10 февраля 2012

Если вы просто хотите суммировать длину ряда массивов, вы можете сделать это напрямую:

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);
}
2 голосов
/ 10 февраля 2012

Вы можете использовать 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...