【发布时间】:2014-09-22 17:54:49
【问题描述】:
我想创建一个常量全局字符数组,这样
- 可用于多个翻译单元。
- 数组的长度是从用于初始化它的字符串文字推导出来的。
- 该字符串文字在我的源文件中仅存在一次(如果可能,在目标文件中)。
- 所有翻译单元都可以在编译时访问长度。
- 当多个翻译单元链接在一起时,没有 ODR 违规。
理论上,这应该可以通过使用const char[] 并将减速/定义放在头文件中以强制数据/符号进入 COMDAT 部分的方式实现,但我不知道标准(甚至任何编译器)都支持。
附言假设使用的任何习语都将用于许多文件中的数百到数千个常量。
编辑:我所知道的给出所有要点的“最干净”的解决方案是:
template<bool> struct data_ {
static const char kFoo[];
};
template<> const char data_<true>::kFoo[] = "bar\0other\0stuff\0";
typedef data_<true> data;
#include <stdio.h>
template<typename T, int N>
void Print(T(&var)[N]) { printf("%d %s\n", N, var); }
int main() { Print(data::kFoo); return 0; }
还是很丑的。
OTOH 如果我只是扔掉 3b(保证相同的存储模块内联),那么这项工作:
const char kFoo[] = "bar\0other\0stuff\0";
因为默认情况下它具有内部链接。一个好的链接器可以合并这些,但此时你不能说地址/标识符的相等性之间的关系(即不要将其转换为指针并将其用作标识)。但这是一个可能几乎一直都是良性的警告。
【问题讨论】:
-
在头文件中,这样的变量(
const而不是extern)会得到内部链接,这意味着每个翻译单元中会有不同的对象。 -
我认为您可以使用类模板的静态数据成员或内联函数中的静态局部变量来满足这些要求。
-
另一个有趣的想法可能是将字符串文字地址和长度分开存储,并让链接器合并这些字符串文字。
-
const& notextern失败点 3b。模板解决方案很丑陋,需要重复名称和大部分类型。函数静态解决方案需要自动返回类型(c++14,还没有)或失败点 4。我不确定单独的存储如何获得所有点的 2、3a 和 4。 -
虽然我通常不提倡使用 Singleton 模式,但制作一个封装字符串文字的 Singleton 类应该满足您的所有要求,但可能要求 4 除外。)“所有翻译单元可以在编译时访问长度”,但可能仍有一些方法可以强制执行。
标签: c++ dry one-definition-rule