为什么外部链接变量可用作常量表达式?

dav*_*mac 15 c++

在另一个问题的讨论中,我得到一个例子,显然标识符的链接在常量表达式中影响了它的可用性:

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
}
Run Code Online (Sandbox Code Playgroud)

最后一个错误(使用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";
                ^
Run Code Online (Sandbox Code Playgroud)

我可能在前面的讨论中错过了这个例子的重要性,因为我认为它不可能仅仅是与之不同的foo<a>联系foo<g>- 但是,我已经开始怀疑这个立场.

  1. 是真的是链接,还是extern允许的其他属性foo<a>()
  2. 允许foo<a>()但不允许的理由是什么foo<g>()?特别地,如果它是由连锁确定,为什么要内部链接导致变量为不可用时为相同的变量声明的常量表达式extern 是可用?
  3. 有人建议,符号在链接器上可见(或不可见)的问题在这里是相关的.对我来说,似乎foo<b>即使static添加了变体仍然允许这个事实反驳了这一点 - 或者我错了?
  4. (之间的差异foo<b>(),并foo<g>()充分所涵盖的其他问题,我认为).

T.C*_*.C. 6

GCC错误.

N3337(这是C++ 11 +编辑修复)[temp.arg.nontype]/2有一个直接在点上的例子:

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
Run Code Online (Sandbox Code Playgroud)

在C++ 03中,引用/指针模板参数仅限于具有外部链接的内容,但在C++ 11中删除了该限制.

在C++ 17中放宽了引用/指针模板参数的规则以允许所有常量表达式,因此GCC接受该示例的原因可能-std=c++1z是它在该模式下经历了不同的代码路径.