指向具有外部链接的对象作为非类型模板参数的指针

时间:2014-12-10 07:50:02

标签: c++ templates static external linkage

如模板标准中所述,其中一个非类型模板参数可以是指向对象的指针。 例如:

template <int* x>
void f()
{}

但是,在实例化期间提供参数时,只允许指向具有外部链接的对象的指针。为什么?为什么标准不允许使用带有内部链接的对象指针来实例化非类型模板?

我在StackOverflow的其他主题中找到了一些解释但我不清楚:

  

模板参数列表中提供的非类型模板参数是一个表达式,其值可以在编译时确定。这些参数必须是:常量表达式,具有外部链接的函数或对象的地址,或静态类成员的地址。

因此,如果我在全局作用域中有static const int x = 10;,那么在编译时是否确定了该对象的地址?

我也在评论中找到了解释:

  

你不知道编译时调用堆栈是什么样的。在你的功能之前,可能已经被称为10个其他或3个其他人或者其他许多人,因此创建字符串的堆栈上的地址可以在呼叫之间变化。当你有一个带有外部链接的对象时,它的地址在编译/链接期间是固定的。

如何更改全局范围内定义的static const int x = 10;的地址?

了解幕后发生的事情会很棒。

1 个答案:

答案 0 :(得分:1)

在C ++ 11中,要求得到了放宽(在C ++ 14中进一步说明),现在[temp.arg.nontype]/1读取:

  

非类型非模板模板参数 template-argument 应为以下之一:
   (...)
   - 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的完整对象的地址,或具有外部或内部链接的函数,包括函数模板和函数模板 - ids 但不包括非静态类成员,表示(忽略括号)为& id-expression ,其中 id-expression 是名称对象或函数的除外,如果名称引用函数或数组,则&可以省略,如果相应的 template-parameter 是引用,则应省略{<1}}

所以在C ++ 11中,这可以编译,如你所愿:

template<int* i> void f(){};
static int x; // even without const
int main() {
    f<&x>();
}