【问题标题】:Warning when dynamically allocating an array of function pointers动态分配函数指针数组时的警告
【发布时间】:2023-04-03 12:25:01
【问题描述】:

我想动态分配一个函数指针数组。以下是我的一些尝试:

#include <type_traits>

void f(int n) {
    // auto p1 = new void(*[n])(); // syntax error

    auto p2 = new (void(*[n])()); // warning, see below

    auto p3 = new typeof(void(*)())[n]; // non-standard extension

    using fptr = void(*)(); auto p4 = new fptr[n]; // verbose, but okay

    auto p5 = new std::add_pointer_t<void()>[n]; // hackish
}

我想知道为什么p2 会导致警告,因为我不能在没有括号的情况下编写它(例如在p1 中)?

(gcc) 警告:必须指定非常量数组的新长度 类型 ID [-Wvla]

周围的括号

(clang) 警告:当类型在括号中时,数组不能有 动态大小

这是一个纯粹的理论问题。我不是在寻找如何编写好的代码来解决问题的建议。

【问题讨论】:

  • auto p6 = std::vector&lt;std::function&lt;void()&gt;&gt;(); 怎么样?
  • 你说“太冗长”的地方,我会说“最容易阅读”
  • @Eljay 是的,这与我在实践中会写的很接近。不过,我的问题纯粹是理论上的。

标签: c++ gcc syntax clang language-lawyer


【解决方案1】:

有一种方法可以在没有某种类型别名的情况下编写此表达式。但这不值得。

new-expression 的语法是

新表达式

     ::opt   new-placementoptnew -type-id new-initializeropt

     ::opt   new-placementopt(type-id) new-initializeropt

新类型 ID

     type-specifier-seq new-declaratoropt

新声明符

     ptr-operator new-declaratoropt

     noptr-new-declarator

ptr 运算符

     * attribute-specifier-seqoptcv-qualifier-seq选择

     &amp; attribute-specifier-seqopt

     &amp;&amp; attribute-specifier-seqopt

     nested-name-specifier * attribute-specifier-seqoptcv-限定符序列选择

noptr-new-declarator

     [ 表达式 ] attribute-specifier-seqopt

     noptr-new-declarator [ constant-expression ] attribute-specifier-seqopt

new-type-id 中使用的 new-declarator 语法符号类似于 type 中使用的 abstract-declarator 符号-id,有三个重要区别:

  • new-declarator 允许在第一组方括号之间使用非常量表达式,以指定动态创建可变大小的数组。 type-id 不是因为“array T of size N”只有当 N 是一个常量表达式时才是有效的 C++ 类型。

  • type-id 允许将 ptr-abstract-declarator 括在括号中,以帮助指定指向数组的指针或指向函数的指针类型,和/或将函数参数列表括在括号中以指定函数类型。 new-declarator 根本不允许使用任何括号! new 关键字后面的任何括号指定一个 new-placement,或一个带括号的 type-id,或一个 new-initializer。 (我想如果 new-type-id 也可以包含括号,那么消除所有这些东西的组合的歧义会非常混乱。)

  • type-id 允许... 省略号标记位于真实声明将具有标识符的位置。这里不是很相关,但这允许未命名的函数参数包,如template&lt;class T&gt; void f(T...);

因此,使用 type-idnew-expression 表单不允许使用您的示例函数需要的可变大小。而使用 new-type-idnew-expression 形式在其语法树中根本不允许任何函数参数列表,因此必须在类型说明符序列。我认为可能性是 type-namedecltype-specifiertypename-specifier

所以我猜 decltype-specifier 选项确实为我们提供了另一种编写表达式的愚蠢冗长的方式,但这次不需要命名类型别名或#include

auto p6 = new decltype(static_cast<void(*)()>(nullptr))[n];

【讨论】:

  • 谢谢!在 StackOverflow 上发帖时,您是手动格式化语法产生式,还是使用一些工具?
  • @VladimirReshetnikov 刚刚输入,有些复制粘贴。
  • 在动态分配指针数组时,我们是否有同样的情况,例如new std::add_pointer_t&lt;int[5]&gt;[n]new decltype((int(*)[5])0)[n]?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-16
  • 1970-01-01
  • 2013-05-26
  • 2017-04-23
  • 2014-10-10
  • 2020-05-17
相关资源
最近更新 更多