【问题标题】:Why is address of non-static member not allowed as template non-type parameter?为什么不允许非静态成员的地址作为模板非类型参数?
【发布时间】:2016-01-31 07:12:51
【问题描述】:
template <int* ip> struct test {};

struct q {
    static int a;
    int b;
    
    constexpr q(int b_) : b(b_) {}
};

int i;
constexpr q q0(2);

int main()
{
    constexpr test<&i> t1;      // Works fine
    constexpr test<&q::a> t2;   // Works 
    constexpr test<&q0.b> t3;   // Does not work; address of non-static member?
    
    return 0;
}

尽管模板参数&amp;q0.b 在编译时已知,但上述代码中的 t3 声明失败。一些谷歌搜索显示标准不允许这样做(第 14.3.2 节):

[注意:数组元素的地址和非静态类成员的名称或地址不是可接受的模板参数。

X x4; // 错误:非静态成员的地址

那么,尽管全局变量的非静态成员的地址是唯一的并且在编译时是已知的,但为什么标准明确不允许这样做呢?

【问题讨论】:

  • 我在 gcc 5.1.1 和 clang 3.5.0 上用 -std=c++11 试过这个
  • No (new q)-&gt;b 在编译时未知
  • 它的类型不是int*,是int q::*,不是吗?
  • @ShafikYaghmour 我删除了它,因为问题更多的是“为什么存在这个限制”而不是“为什么这段代码不能编译?”无论哪种方式,这两种措辞都是不允许的。
  • 模板参数必须被破坏,并且破坏(任意复杂)对子对象的引用是一大堆蠕虫。

标签: c++ templates language-lawyer


【解决方案1】:

首先,要使用指向子对象的指针/引用,您需要能够破坏它们。这是一项艰巨的任务。

其次,也许更重要的是,来自N4198

常量表达式必须命名完整的限制 保留对象以避免指针的别名问题 子对象:

struct A { int x, y; } a;
template<int*> struct Z;
using B = Z<&a.x + 1>;
using C = Z<&a.y>;
// Are B and C the same type?

引用Richard Smith

“是”的答案是有问题的,因为有些事情你可以做 带有指向 [a.y] 的指针,如果 在超过 [a.x] 末尾的指针上执行答案“否”是 有问题的,因为它们(在典型的实现中)代表 同一个地址。

【讨论】:

  • +,简而言之,主要因素。
  • @T.C.如果 x 和 y 是静态成员或简单的全局变量,我们不会遇到同样的情况吗? (我不是 C++ 专家;我只是想理解 :))
  • @T.C.您对 Richard Smith 的引用似乎提供了更合理的论点:“请记住,模板参数必须是可以在编译时合理确定并且可以修改的东西。通用指针在编译时是未知的(运行时链接器可以移动周围的东西),对于如何在所有平台上对它们进行破坏,不一定有明确的规则。”
【解决方案2】:

用这段代码替换你的main

int main(void)
{    
constexpr static int bb = 5;    
constexpr test<&bb> t;    
return 0;
}

你会收到错误 bb cannot be used as a template argument because it has no links (不要误认为链接器相关人员)。

除非通过对象引用类数据成员,否则无法访问它们,并且在模板实例化期间不能考虑,因为数据成员没有链接,即它们不是定义的符号,因此不能用作模板参数。

话虽如此,做一个 readelf 你可以验证这一点:

48: 00000000004006ac     4 OBJECT  LOCAL  DEFAULT   14 q0


68: 000000000060097c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
69: 0000000000600978     4 OBJECT  GLOBAL DEFAULT   23 q::a

但没有定义q0.b。另一种方法是命名(mangle)非静态类成员,这会剥夺语言的动态功能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 2016-11-04
    • 2011-07-29
    • 1970-01-01
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多