如何将VLA传递给功能模板?

时间:2014-02-13 07:36:25

标签: c++ arrays templates variable-length-array gcc-extensions

我有以下无法遵守的代码。

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 个答案:

答案 0 :(得分:2)

问题是c ++不支持可变大小的数组,并且仅支持编译器扩展。这意味着,标准没有说明应该发生什么,你应该看看你是否可以在编译器的文档中找到,但我怀疑是否记录了这些极端情况。

所以,这就是问题所在:

int arr[n];

解决方案是避免它,并使用c ++支持的东西,例如std::vector

答案 1 :(得分:1)

我认为编译器不能推断出模板中可变长度数组的大小。另外,在使用之前不要忘记转发声明f。可变长度数组是GCC扩展,您应该收到有关其使用的警告。

答案 2 :(得分:1)

您可以声明您的功能:

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

答案 3 :(得分:0)

当您使用可变长度数组(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);
}

答案 4 :(得分:0)

必须在编译时解析模板参数。

参数size_t N的函数模板无法匹配任何类型的数组或其他大小来自运行时输入的容器。

您需要提供array_1d_ini的另一个版本,其大小不是模板参数。

答案 5 :(得分:-1)

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