【问题标题】:How to pass a VLA to a function template?如何将 VLA 传递给函数模板?
【发布时间】:2014-03-11 23:00:05
【问题描述】:

我有以下无法编译的代码。

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.......

【问题讨论】:

  • 你得到什么错误?请注意,您可以像这样对数组的元素进行零初始化:int arr[10] = {};
  • 只要定义了size_t,代码应该没有问题。就目前的问题而言,答案是“这是正确的方法”。需要更多信息来诊断问题。
  • 为我编译。你有什么错误?你用什么编译器?
  • 您需要包括例如&lt;stddef.h&gt; 代表 size_t(或 &lt;cstddef&gt; 并说 using std::size_t)以保证您的代码示例无需进一步更改即可编译。
  • @user29561 是的,没关系。请发布一个简单的代码示例来重现该问题。否则我们只是猜测:)

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


【解决方案1】:

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

【讨论】:

  • 我不认为iostream 可以保证定义size_t
  • @juanchopanza 也许吧。我在标准中找到了这个(不确定是否断章取义):However, referring to std or std::size_t is ill-formed unless the name has been declared by including the appropriate header. — end note ]
  • 按照标准std::size_t定义在&lt;cstddef&gt;(通常和::size_t&lt;stddef.h&gt;一样。iostrem经常使用它,但标准不要求streampos与 size_t 相同(或与...兼容)。这只是在 size_t 为 64 位无符号的平台上非常常见的实现,但不是标准要求。因此,实际上“iostream”不允许定义 size_t
  • @Emilio 看来这个答案在新的编辑中已经失效了。
  • 重点是std::size_t 甚至可能与::size_t 不一样,尽管没有实现者将它们区别开来,否则大多数现有的 cod 都会崩溃...
【解决方案2】:
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;
}

【讨论】:

  • OP 的解决方案适用于固定大小的数组。但是 OP 使用 VLA 的编译器扩展。
【解决方案3】:

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

所以,这就是问题所在:

int arr[n];

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

【讨论】:

    【解决方案4】:

    你可以这样声明你的函数:

    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&lt;int&gt; arr(n, 0); 或者,您可以在需要时使用来自&lt;algorithm&gt;fill 填充它: std::fill(arr.begin(), arr.end(), 0);

    【讨论】:

    • 好吧,OP 正在尝试创建本地 VLA。无论如何,他将数组的大小传递给函数,那么为什么不能将它传递给array_ini_1d?模板没有任何理由,除了演绎技巧,它被 VLA 的使用打败了。
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

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

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

      您需要提供另一个版本的array_1d_ini,它没有将大小作为模板参数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-25
        • 1970-01-01
        • 2017-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多