为什么外部链接变量可用作常量表达式
Why are external-linkage variables usable as constant expressions?
在另一个问题的讨论中,我得到了一个例子,显然标识符的链接影响了它在常量表达式中的可用性:
extern char const a[] = "Alpha";
char constexpr b[] = "Beta";
char const g[] = "Gamma";
template <const char *> void foo() {}
auto main()
-> int
{
foo<a>(); // Compiles
foo<b>(); // Compiles
foo<g>(); // Doesn't compile
}
最后一个错误(使用GCC)是:
test.cc: In function 'int main()':
test.cc:12:13: error: the value of 'g' is not usable in a constant expression
foo<g>(); // Doesn't compile
^
test.cc:3:16: note: 'g' was not declared 'constexpr'
char const g[] = "Gamma";
^
我可能在前面的讨论中错过了这个例子的意义,因为我认为区分foo<a>
和foo<g>
的不可能仅仅是连锁——然而,我开始怀疑这种立场。
- 是真的链接,还是
extern
授予的其他属性,允许foo<a>()
? - 允许
foo<a>()
而不允许foo<g>()
的基本原理是什么?特别是,如果它是由链接决定的,当声明为extern
的相同变量可用时,为什么内部链接会导致变量不能用作常量表达式呢? - 有人建议,符号对链接器可见(或不可见)的问题与此相关。对我来说,事实似乎
foo<b>
变体仍然被允许,即使添加static
反驳了这一点-或者我错了吗? - (
foo<b>()
和foo<g>()
之间的差异已被其他问题充分涵盖,我认为)。
GCC bug。
N3337(这是c++ 11 +的编辑修复)[temp.arg.]Nontype]/2有一个直接在point上的例子:
template<class T, const char* p> class X {
/* ... */
};
X<int, "Studebaker"> x1; // error: string literal as template-argument
const char p[] = "Vivisectionist";
X<int,p> x2; // OK
在c++ 03中,引用/指针模板参数仅限于具有外部链接的东西,但在c++ 11中删除了该限制。
引用/指针模板参数的规则在c++ 17中放宽了,允许所有常量表达式,所以GCC接受-std=c++1z
示例的原因可能是它在该模式下经历了不同的代码路径。
这是一个奇怪的巧合。我昨晚刚刚在 c++模板中读到这一点。当使用指针作为模板非类型形参时,它是指针中包含的地址,而不是指针所指向的作为模板实参的常量的值。因此,地址必须在编译时是可知的,并且在所有编译单元中是唯一的,以避免违反ODR。这对于constexpr
和extern
变量是正确的,但对于具有文件或全局链接的变量则不是。下面是一个例子。
static char const foo[] = "Hello";
char const bar[] = "Hello";
constexpr char const baz[] = "Hello";
extern char const qux[] = "Hello";
template <char const*>
struct my_struct{};
int main() {
my_struct<foo> f; // ERROR: Address is unique, but not known until runtime
my_struct<bar> b; // ERROR: Address may or may not be unique (ODR violation) and not known until runtime
my_struct<baz> bz; // OK: constexpr
my_struct<qux> q; // OK: extern
}
相关文章:
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 使用自动推导的 lambda 参数作为常量表达式
- 生成提升::hana::set 的常量表达式问题
- 为什么不能用常量表达式声明数组?
- 不是 lambda 函数中的常量表达式
- 函数调用在常量表达式中必须具有常量值
- 错误:constexpr 变量'struct2Var'必须由常量表达式初始化
- 关于在需要常量表达式的上下文中使用的glvalue常量表达式的问题
- 生成 constexpr 字符串表,不能产生常量表达式
- 整体模板参数。错误:在常量表达式中使用'this'
- 如何在满足常量表达式的同时将整数传递给指针,传递给 std::array<double、integer>?
- 编译器错误:函数调用在常量表达式中必须有一个常量值
- 错误:'new'不能出现在常量表达式中
- 我可以写出小于 -0.5 两个 ulps 的常量表达式双精度吗?
- 编译器在传递 const 变量时返回错误:模板参数不是常量表达式
- 为什么我不能在非常量表达式上使用此模板阶乘函数?
- C++ 使用变量而不是常量表达式初始化数组
- 使用函数参数作为常量表达式的一部分 - gcc vs clang
- 片段着色器中的"错误:在 GLSL 1.30 及更高版本中禁止使用非常量表达式索引的采样器数组"