模板不会推断 C++ 中零长度数组的大小

2024-01-08

假设我有一个模板函数,它可以推断数组参数的长度。

template <size_t S>
void join(const char d[], const char *(&arr)[S]) { }

如果我这样称呼它,一切都很好:

const char *messages[] = {
    "OK",
    "Not OK",
    "File not found"
};
join("\n", messages);

但如果我用空数组调用它,如下所示:

const char *messages[] = { };
join("\n", messages);

...它无法编译(使用 clang 4.0):


targs.cpp:9:5: error: no matching function for call to 'join'
    join("\n", messages);
    ^~~~
targs.cpp:4:6: note: candidate template ignored: substitution failure [with S = 0]
void join(const char d[], const char *(&arr;)[S]) { }
     ^
1 error generated.  

我猜测这与 C++ 不喜欢零长度数组有关,但如果该函数不是模板并将长度作为单独的参数,它不会抱怨我将消息声明为零长度大批。

这是怎么回事,有什么好的解决方法吗?


我的实际用例是定义 HTTP API 端点采用的参数,如下所示:

const api_param_t params[] = {
    { API_TYPE_STRING, "foo" },
    { API_TYPE_UINT64, "bar" },
    { API_TYPE_STRING, "baz" }
}
const api_status_t status_codes[] = { … };
const api_middleware_t middleware[] = { … };

new api_endpoint("/foo", params, status_codes, middleware);

大多数端点至少采用一个参数,但许多端点不采用任何参数。看起来这确实是 GCC 和 clang 都实现的扩展(但是,看起来并不完全......)。我可以想到一些解决方法:

  • Overload the api_endpoint constructor to special case zero-length arguments (but I need 23 of them to cover each zero-length-able parameter), which the GCC/clang extension is OK with.

  • 不要尝试推断数组长度,将其作为单独的参数(并继续使用零长度数组)

  • 对这些参数使用更高级别的数据结构(例如向量)

  • 使用魔法值来表示“空”

…但如果有人有更好的想法,我很想听听


这段代码首先是不合法的:

const char *messages[] = { };

以下是我的编译器产生的错误和警告:

main.cpp:6:26: warning: zero size arrays are an extension [-Wzero-length-array]
const char *messages[] = { };
                         ^
main.cpp:7:1: error: no matching function for call to 'join'
join("\n", messages);
^~~~
main:3:6: note: candidate template ignored: substitution failure [with S = 0]: zero-length arrays are not permitted in C++
void join(const char d[], const char *(&arr)[S]) { }
     ^                                       ~
1 warning and 1 error generated.

所以实际上根本不允许零长度数组。您的编译器似乎有零长度数组的扩展,但是,它不涵盖这种特定情况。扩展有时就是这样,因为扩展的工作量较少,可以使它们与整个语言一致地工作。

解决方法取决于您为什么需要零长度数组以及您在其他地方如何使用它。一种解决方法可能是使用单元素数组。


这是一个解决方法。由于扩展不允许将数组大小推导为零,因此添加不需要此推导的重载:

template <size_t S>
void join(const char d[], const char *(&arr)[S]) {
    std::cout << "array length > 0\n";
}

void join(const char d[], const char *(&arr)[0]) {
    std::cout << "extension, zero length array\n";
}

int main() {
    const char *messages[] = {
        "OK",
        "Not OK",
        "File not found"
    };
    join("\n", messages);

    const char *messages2[] = { };
    join("\n", messages2);
}

您应该记住,这是使用扩展,而不是可移植代码。您可能更喜欢编写可移植代码,以避免被锁定到任何特定的 C++ 实现。您可以通过添加标志来查看您对该扩展的依赖程度-Wzero-length-array到你的构建。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

模板不会推断 C++ 中零长度数组的大小 的相关文章

随机推荐

  • 用 Ruby 实现树

    至于Ruby中我们没有像C 那样的指针 我们如何实现树 您不一定需要指针或引用来构建树 对吗 这是一个基本示例 class Tree attr accessor children value def initialize v value v
  • 如何将 MFC ActiveX 控件添加到现有的 ActiveX 项目

    在 Visual Studio 2008 中 我可以创建一个 MFC ActiveX 项目 它提供了一个创建单个 ActiveX 控件的向导 我现在想在这个项目中创建新的控件 我找不到任何方法来做到这一点 我刚刚发现生成 ActiveX 控
  • 使用 cin 进行整数输入时捕获字符串[重复]

    这个问题在这里已经有答案了 我在 google stackoverflow 上看到过类似的帖子 然而 我找不到一个足够接近我的场景的方法 而且我对 C C 的了解也不够深 无法将其他建议移植到我的方法中 也许这本身就是一个标志 无论如何 这
  • 如何让 TortoiseSVN 始终冻结标签的 svn:externals

    tortoiseSVN 可以做到这一点吗 总是冻结svn externals对于标签 场景是我们的主干将始终使用外部的 HEAD 修订版 但是当我们创建 标签 时 我们希望它们为外部设置修订版 以便在特定时间点正确 冻结 它们 Update
  • AJAX 请求是否保留 PHP 会话信息?

    如果我有一个用户登录到我的网站 他的 ID 存储在 SESSION 然后从他的浏览器中单击 保存 按钮 这将向服务器发出 AJAX 请求 他的会 SESSION并且 cookie 会保留在该请求中 我可以安全地依赖 id 中存在的信息吗 S
  • VideoJS 进度事件在 Safari 5.1 上始终为 0

    我在 Safari 5 1 上使用 VideoJS 播放视频时遇到这种奇怪的行为 如果我听进度事件 var player videojs player id preload auto techOrder html5 player on pr
  • 创建并流式传输图像存档 zip 文件以供下载 C#

    我正在 MVC3 中使用深受喜爱的 DotNetZip 归档库来动态生成 Zip 文件 其中包含来自存储在数据库中的二进制文件的 png 图像 然后 我将生成的 Zip 文件流式传输出来供用户下载 我在保存到数据库之前验证图像数据 因此您可
  • 全屏 UIView,状态栏和导航栏覆盖在顶部

    实现 UIView 顶部的状态栏和导航栏的正确方法是什么 替代文本 http img skitch com 20081217 t78sdixk37hqgdh1ia2fgec4st png http img skitch com 200812
  • IValidatableObject 对于 EF 导航属性没有用?

    仅当实现实体 DbEntityEntry State 不同于 Unchanged 时 才会调用 IValidatableObject Validate 仅更改导航属性不会更改状态 因此永远不会发生验证 为什么微软总是发布半生不熟的测试版东西
  • 多媒体内容的处理程序 (MIME) 不起作用

    我正在与一个在页面中呈现多媒体内容的处理程序合作 这个想法是 该处理程序访问文件并使用扩展名确定类型 然后将其呈现problem是大多数时候处理程序本身被下载并且不提供多媒体 这是代码 FileInfo file new FileInfo
  • 如何更改树莓派的屏幕分辨率[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在 Raspberry pi 上使用 7 TFT LCD 显示屏 谁能告诉我如何更改 Raspberry Pi 的屏幕分辨率以及 7 T
  • 在 CXF JAX-WS 单向方法调用中获取客户端 IP 地址的可靠方法

    我使用以下代码来获取 JAX WS 单向方法调用的客户端 IP 地址 protected HttpServletRequest getServletRequest MessageContext ctx wsContext getMessag
  • AttributeError:“dict”对象没有属性“drop_duplicates”

    运行此代码时 我收到 AttributeError dict object has no attribute drop duplicates 有什么想法如何解决这个问题吗 第一个模块接口 py import tkinter as tk fr
  • Tkinter - 如何改进“grab_set()”方法行为?

    我编写了一个简单的代码 其中有一个带有两个按钮的主窗口 第一个打开一个新窗口 第二个打开一个消息框 当我打开消息框窗口时 我无法以任何方式与主窗口进行文字交互 如果我单击它 系统铃声会响起并且消息框会闪烁 我想在另一个窗口复制相同的行为 但
  • 在英国的 iPhone 上查看时,从 SSRS 呈现的 Excel 丢失货币符号

    我们的报告动态地格式化货币 因此 在结果集中有一列名为CurrencyFormatString 这通过 FORMAT FieldName CurrencyFormatString 应用于适当的字段 一切似乎都工作正常 直到将报告呈现为 Ex
  • 对矩阵列表求和[重复]

    这个问题在这里已经有答案了 我有一个列表 其中每个元素都是 5 5 矩阵 例如 1 V1 V2 V3 V4 V5 1 0 000000 46 973700 21 453500 338 547000 10 401600 2 43 020500
  • 从谷歌地图 api json 获取 formatted_address

    我想从 json 数组中获取 formatted adress 一个示例链接可以是http maps googleapis com maps api geocode json latlng 55 397563 http maps googl
  • OS X 10.9 Beta 6 上禁用 Eclipse 菜单

    今天我像往常一样打开了日食 但我无法做任何事情 除首选项外的所有菜单均呈灰色 禁用 我使用的是 Mac Mavericks Beta 6 和 Eclipse Kepler 你有什么提示给我吗 重启Eclipse或者整个mac都没有解决问题
  • 用于 beta 测试的 Ad Hoc 发行版 xcode 4.3

    遵循来自的精彩教程后http www raywenderlich com http www raywenderlich com 关于如何将您的应用程序提交到应用程序商店 我从一开始就开始计划我的 Beta 测试计划 我不会详细介绍一切顺利的
  • 模板不会推断 C++ 中零长度数组的大小

    假设我有一个模板函数 它可以推断数组参数的长度 template