为什么 CRTP 模板的派生类不初始化静态变量?

问题描述 投票:0回答:1

所以我正在尝试创建一个基于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: 程序返回

0
https://godbolt.org/z/5c74TePT5。我期望它打印
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;
    }
    ...
}

但问题是,我仍然不知道为什么它可以解决问题。即使在我这样做之后,

DoRegister
似乎只有在类定义之外有一个空构造函数或默认构造函数时才会被调用,如全局地图大小所示只有2:https://godbolt.org /z/Me53q1x86.

这里发生了什么?

templates c++17 factory derived-class crtp
1个回答
0
投票
  1. 隐式实例化

    除非模板类的成员是已声明的特化,否则当在需要成员定义存在的上下文中引用特化时,或者如果成员定义的存在影响了语义,则该成员的特化会被隐式实例化。该程序;特别是,静态数据成员的初始化(以及任何相关的副作用)不会发生,除非静态数据成员本身的使用方式需要静态数据成员的定义存在。

    TL;DR 如果没有使用,则不会实例化。

  2. 显式默认函数

    未定义为已删除的非用户提供的默认函数(即在类中隐式声明或显式默认)在使用 odr([basic.def.odr])或需要进行常量求值时会隐式定义([expr.const]).

    TL;DR

    =default
    在类中只声明一个事物;如果未使用,则未定义。

© www.soinside.com 2019 - 2024. All rights reserved.