Как передать VLA в шаблон функции?

У меня есть следующий код, который не может быть соблюден.

using namespace std;
void f(int);
template<typename T1, size_t N>
void array_ini_1d(T1 (&x)[N])
{
  for (int i = 0; i < N; i++)
  {
    x[i] = 0;
  }
}

Как правильно передать массив, если main что-то вроде ниже?

int main()
{
  int a;
  cin >> a;
  int n = a / 4;
  f(n);
  return 0;
}

void f(int n)
{
  int arr[n];
  array_ini_1d(arr);
}

ошибка: нет подходящей функции для вызова array_ini_1d..............

6 ответов

Решение

Я не думаю, что компилятор может определить размер массива переменной длины в шаблоне. Кроме того, не забудьте переслать объявить f прежде чем использовать его. Массивы переменной длины являются расширением GCC, и вы должны получить предупреждение об их использовании.

Проблема в том, что массивы переменного размера не поддерживаются C++ и поддерживаются только как расширение компиляторов. Это означает, что стандарт не говорит о том, что должно произойти, и вы должны посмотреть, сможете ли вы найти его в документации компилятора, но я сомневаюсь, что такие угловые случаи задокументированы.

Итак, это проблема:

int arr[n];

Решение состоит в том, чтобы избежать этого и использовать что-то, поддерживаемое C++, как, например, std::vector,

Параметры шаблона должны быть разрешены во время компиляции.

Нет способа, чтобы шаблон функции с параметром size_t N может соответствовать любому виду массива или другого контейнера, размер которого поступает из входных данных во время выполнения.

Вам нужно будет предоставить другую версию array_1d_ini который не имеет размер в качестве параметра шаблона.

Поскольку вы используете массив переменной длины (VLA) (расширение компилятора), компилятор не может вывести N.

Вы должны передать его указателем и указать размер:

template<typename T>
void array_ini_1d(T* a, std::size_t n)
{
    for (std::size_t i = 0; i != n; ++i) {
        a[i] = 0;
    }
}

void f(int n)
{
    int arr[n];
    array_ini_1d(arr);
}

Или использовать std::vector, (расширение не используется так). Который кажется чище:

template<typename T>
void array_ini_1d(std::vector<T>& v)
{
    for (std::size_t i = 0, size = v.size(); i != n; ++i) {
        a[i] = 0; // or other stuff.
    }
}

void f(int n)
{
    std::vector<int> arr(n); // or arr(n, 0).
    array_ini_1d(arr);
}

Вы можете объявить свою функцию следующим образом:

template <typename A, size_t N> void f(A a[N]) {
    for(size_t i = 0; i < N; i++)
        cout << a[i];
}

Однако проблема в том, что при вызове функции компилятор не будет выводить параметры шаблона, и вам придется указывать их явно.

char arr[5] = {'H', 'e', 'l', 'l', 'o'};

int main()
{
    //f(arr); //Won't work
    f<char, sizeof(arr)/sizeof(arr[0])>(arr);
    cout << endl;
    return 0;
}

К сожалению, это разрушает саму идею...

UPD: И даже этот код НЕ работает для массива с переменной длиной, поскольку длина вычисляется во время выполнения, а параметры шаблона определяются во время компиляции.

UPD2: при использовании std::vector Вы можете создать его инициализированным:vector<int> arr(n, 0);Или вы можете заполнить его fill от <algorithm> при необходимости:std::fill(arr.begin(), arr.end(), 0);

template<typename T, size_t N>
void f(T* a)
{
/* add your code here */
}

int main()
{
    int a[10];
    f<int, 10>(a);
    return 0;
}
Другие вопросы по тегам