【问题标题】:template pointer parameter pack模板指针参数包
【发布时间】:2018-02-12 18:23:31
【问题描述】:

为什么不能用同一个指针的偏移量实例化带有指针模板参数包的模板函数?

我的意思是:鉴于这段简短的代码,为什么我必须注释掉最后两行?

template <int * ... pt> void f() {}

int n[] = {1, 2, 3};
int m = n[1];

int main()
{
    f<n>();  // this is accepted
    f<n, &m>();  // this is accepted too
    //f<n, n+1>(); // this is not.
    //f<n, &n[1]>(); // this isn't accepted neither
}

n+1 不代表与 &amp;m 相同的地址吗?还是联动有区别?或者还有什么?

【问题讨论】:

  • m 是它自己的变量; &amp;mn 无关。
  • 试试int * p = &amp;n[0]; f&lt;p&gt;(); 以获得很好的解释。

标签: c++ templates language-lawyer variadic-templates


【解决方案1】:

cppreference.com - Template non-type arguments

  • 对于指向对象的指针,模板参数必须指定具有静态存储持续时间和链接(内部或外部)的对象的地址,或计算为适当空指针或 std::nullptr_t 值的常量表达式.

...

唯一的例外是引用和指针类型的非类型模板参数不能引用/作为地址

  • 子对象(包括非静态类成员、基子对象或数组元素);
  • 一个临时对象(包括在引用初始化期间创建的一个);

所以数组元素的地址是不允许的。

【讨论】:

  • 作为参考,关于子对象的引用位(c++17-relevant)源自this section of the Standard。第一个引用的项目符号描述了 c++17 之前的版本,我认为遗漏了重要的一点,即它必须是规范中描述的 complete 对象的地址。 c++17 之前的规范还明确指出“数组元素的地址...不是可接受的模板参数”。
【解决方案2】:

在 C++17 中,来自[temp.arg.nontype]

对于引用或指针类型的非类型模板参数,常量表达式的值不应引用(或对于指针类型,不应是地址):

  • 一个子对象,
  • [...]

子对象在哪里,来自[intro.object]

对象可以包含其他对象,称为子对象。子对象可以是成员子对象 ([class.mem])、基类子对象 ([class.derived]) 或数组元素。

使用&amp;m 作为非类型模板参数很好——它指向一个对象。该对象恰好是从n[1] 初始化的,但这并不重要。

另一方面,n+1&amp;n[1] 都指向数组n 的一个元素,也就是说它们都指向n 的子对象,因此这是不允许的。 n+1&amp;m 不相关。


C++11C++14中,措辞是inclusive而不是exclusive,但结论是一样的:

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

  • [...]
  • 一个常量表达式 ([expr.const]),它指定具有静态存储持续时间和外部或内部链接的 完整对象 的地址或具有外部或内部链接的函数,包括函数模板和函数模板 ID,但不包括非静态类成员,表示(忽略括号)为 [...]
  • [...]

允许使用指向m 的指针,不允许使用指向n[1] 的指针。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-03
    • 1970-01-01
    相关资源
    最近更新 更多