提问人:ashura 提问时间:7/27/2023 最后编辑:ashura 更新时间:7/27/2023 访问量:57
为什么 CRTP 模板中的派生类不初始化静态变量?
Why does a derived class from CRTP template not initialise the static variables?
问:
所以我正在尝试创建一个基于 CRTP 的工厂。为简单起见,我将只包括此处相关的任何内容。我有两个可能彼此无关的问题,但试图找到关键字时遇到了困难。
#include <bits/stdc++.h>
using namespace std;
static auto& GetFactoryMap() {
static vector<string> GLOBAL_FACTORY_MAP;
return GLOBAL_FACTORY_MAP;
}
template <typename Derived>
struct Registrar {
static int DoRegister() {
auto name = typeid(Derived).name();
GetFactoryMap().emplace_back(name);
return 1;
};
inline static const int _hello = DoRegister();
};
struct Foo : public Registrar<Foo> {};
int main() {
cout << GetFactoryMap().size();
}
用 , 标志 编译。x86-64 clang-8.0.0
-std=c++17
问题 1:程序返回:https://godbolt.org/z/5c74TePT5。我希望它打印出来,因为定义类也应该定义一个 ,这反过来将初始化 和 调用。0
1
Foo
Registrar<Foo>
_hello
DoRegister()
但是当我这样做时:
int main() {
cout << Foo::_hello << endl;
cout << GetFactoryMap().size();
}
然后它确实打印了()和(地图大小)。1
_hello
1
问题 2:所以我发现了如何通过在构造函数内部调用虚拟调用来解决第一个问题。_hello
Registrar
template <typename Derived>
struct Registrar {
Registrar() {
(void)_hello;
}
...
}
但问题是,我仍然不知道为什么它可以解决这个问题。即使在我这样做之后,似乎只有当我有一个空构造函数或类定义之外的默认构造函数时才会被调用,如全局地图大小仅为 2:https://godbolt.org/z/Me53q1x86 所示。DoRegister
这是怎么回事?
答:
-
除非模板化类的成员是声明的专用化,否则当在要求成员定义存在的上下文中引用该专用化时,或者如果成员定义的存在影响程序的语义,则隐式实例化该成员的专用化;具体而言,除非静态数据成员本身以需要静态数据成员定义存在的方式使用,否则不会发生静态数据成员的初始化(以及任何关联的副作用)。
TL的;DR 如果未使用,则不会实例化。
-
未定义为删除的非用户提供的默认函数(即,在类中隐式声明或显式默认)在使用 odr ([basic.def.odr]) 或需要常量计算 ([expr.const]) 时隐式定义。
TL的;类中的 DR 只声明一个事物;如果未使用,则未定义。
=default
评论
Hi()=default
Hi::Hi() = default
Hi::Hi() = default
评论