23

在回答这个 SO question& id-expression时,我在标准(已经是 C++03,仍在 C++11 中)中发现,如果地址的格式为(加上一些例外),则只能将地址用作非类型模板参数。

但我无法回答为什么会这样。

14.3.2 模板非类型参数 [temp.arg.nontype]

非类型、非模板模板参数的模板参数应为以下之一:

[...]

— 一个常量表达式 (5.19),它指定具有静态存储 > 持续时间和外部或内部链接的对象或具有外部或内部链接的函数的地址,包括函数模板和函数模板 ID,但不包括非静态类成员,表示(忽略括号)为 & id-expression,但如果名称引用函数或数组,则 & 可以省略,如果相应的模板参数是引用,则应省略;[...]

(n3485,强调我的)

例子:

using TFoobar = int (*)();
template < TFoobar tp > struct foo_struct{};

int foobar() { return 42; }
constexpr TFoobar pFoobar = &foobar;

foo_struct < &foobar > o0; // fine
foo_struct < pFoobar > o1; // ill-formed

我想这与翻译阶段有关,即编译器对地址了解不多。然而,为什么不允许呢?编译器不应该使用类似于宏替换的东西来替换pFoobar&foobar

4

2 回答 2

2

考虑类Foo<&X>Foo<&Y>,两者都具有静态成员int Bar。链接器必须能够判断您的程序是否有 1 个或 2 个Bar对象。&X现在考虑链接器也是最有可能负责为和赋值的一方&Y

再看标准。正如它所写的,编译器不需要将实际地址传递给链接器。相反,它通过id-expression. 链接器已经非常有能力确定两个id-expression' 是否相同,甚至在为它们分配数字地址之前。

于 2013-04-08T20:30:19.737 回答
0
  1. 它不能是变量,因为变量仅在运行时设置。
  2. 它不能是 a constexpr,因为在编译时无法知道地址的值;在大多数情况下,它只会在执行前重新定位后修复。
  3. 理论上它可能是一个算术表达式(即使它在标准中是不允许的),但在数组元素地址的常见情况下,您可以简单地使用&arr[i]而不是arr + i.
于 2013-04-08T20:30:54.987 回答