为什么不允许非静态成员的地址作为模板非类型参数
Why is address of non-static member not allowed as template non-type parameter?
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;
}
尽管在编译时已知模板参数&q0.b
但上述代码段中的 t3 声明失败。一些谷歌搜索显示,这是标准所不允许的(第14.3.2节(:
[注意:数组元素的地址和非静态类成员的名称或地址是不可接受的模板参数。
X<&s.m> x4;//error: non-static membe 的地址
那么,为什么标准明确禁止这样做,尽管全局变量的非静态成员的地址是唯一的,并且在编译时是已知的?
首先,要使用指向子对象的指针/引用,您需要能够破坏它们。这是一项相当大的任务。
其次,可能更重要的是,来自 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?
引用理查德·史密斯的话,
答案"是"是有问题的,因为有些事情你可以做 带有指向 [
a.y
] 的指针,如果 在经过 [a.x
] 末尾的指针上执行,答案"否"是 有问题,因为它们(在典型实现中(表示 相同的地址。
用
这段代码替换你的 main
int main(void)
{
constexpr static int bb = 5;
constexpr test<&bb> t;
return 0;
}
并且您将收到错误bb不能用作模板参数,因为它没有链接(不要与链接器相关人员混淆(。
类数据成员除非通过对象引用,否则无法访问它们,并且在模板实例化期间不能考虑它们,因为数据成员没有链接,即它们不是定义的符号,因此不能用作模板参数。
话虽如此,做一个读数,你可以验证这一点:
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(non静态类成员,这将剥夺语言的动态功能。
相关文章:
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 如何获取C++字符数据类型的地址
- 如何解决一元"*"(有"字符")错误的无效类型参数?
- "std::shared_ptr":不是参数"_Ty"的有效模板类型参数
- 具有可变参数非类型参数的模板专用化
- 函数类型参数的模板参数推导
- PowerShell 使用结构类型参数调用 C++ DLL 的导出函数
- 对于非常量指针类型的参数,未调用具有常量指针模板类型参数的功能
- 为模板传递非类型参数 agument
- 为什么带有类型参数的运算符 () 可以应用于 result_of 上下文中的类型?
- 使用其他模板类型参数作为要在函数签名中使用的类型别名声明
- 如何避免具有相同类型参数的函数中的错误
- 将内置类型变量传递给只有一个类类型参数的"+"运算符函数时自动类型转换的构造函数
- c++非类型参数包扩展
- 如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)
- 在不同的模板参数包之间分发非类型参数包
- 如何在使用容器和字符串时强制使用显式分配器类型参数
- 错误:一元"*"的类型参数无效(具有"int"):使用 mergesort 计算
- EXPECT_CALL具有 unique_ptr 引用类型参数的模拟函数
- 为什么不允许非静态成员的地址作为模板非类型参数