V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yazoox
V2EX  ›  C++

这里有一段代码,有一些小细节,不是很明白。请教一下

  •  
  •   yazoox · 2021-04-30 09:05:15 +08:00 · 3202 次点击
    这是一个创建于 1282 天前的主题,其中的信息可能已经有所发展或是发生改变。
    // 1
    struct Base
    {
        int retCode {};
        std::string retErrorString;
    };
    
    // 2
    template <typename Type>
    struct EventResult : Base
    {
        Type retValue {};
    };
    
    // 3
    template <>
    struct EventResult<void> : Base {};
    

    代码段 1 中间的 int retCode 后面为什么要添加一对{},代码 2 也有类似的,Type retValue {} 代码段 2 已经定义好了模板,为什么要添加代码段 3 ?

    第 1 条附言  ·  2021-04-30 10:28:53 +08:00
    忘记说了,这段代码是某工具自动生成的。我看到了,觉得很“奇怪”,就来问问。
    24 条回复    2021-04-30 22:47:26 +08:00
    leimao
        1
    leimao  
       2021-04-30 09:10:56 +08:00
    1 和 2 是 C++ Explicit Constructor,语法规范,减少歧义。但是他这个{}里面不放个数,也是挺 confusing 的。
    https://leimao.github.io/blog/CPP-Explicit-Constructor/
    leimao
        2
    leimao  
       2021-04-30 09:13:53 +08:00
    3 感觉就是给 void 这个 type 弄一个特殊的 definition 。
    因为
    ```
    void retValue {};
    ```
    是会报错的。
    jonah
        3
    jonah  
       2021-04-30 09:17:25 +08:00
    @leimao initializer_list 不放个数,表示调用默认构造。
    leimao
        4
    leimao  
       2021-04-30 09:18:56 +08:00
    @jonah 个人认为这个是不好的习惯,必须改掉。
    3dwelcome
        5
    3dwelcome  
       2021-04-30 09:44:44 +08:00
    一楼说的对。
    可这代码需要加--std=c++xx, 如果不加,编译就直接报:error C2063: 'retCode' : not a function

    总觉得直接写 int retCode = {0},大家也能猜到是调用构造函数啊,一缩写反而看不太懂。
    bestwaytowait
        6
    bestwaytowait  
       2021-04-30 09:46:10 +08:00
    其实这个算 Uniform Initialization
    Tony042
        7
    Tony042  
       2021-04-30 09:47:56 +08:00
    @leimao initializer_list 置空是没问题的,书上有大量这样的写法,主要是默认初始化一切变量,尤其是指针,要是指针不置为 nullptr,碰巧指向内存里的一处位置,后续很可能会出现奇奇怪怪的 bug 。
    lonewolfakela
        8
    lonewolfakela  
       2021-04-30 09:48:41 +08:00
    @leimao 使用 empty initializer 进行初始化叫做 Value initialization ( https://en.cppreference.com/w/cpp/language/value_initialization ),对于整数类型,Value initialization 意味着初始化为 0 值(Zero initialization,https://en.cppreference.com/w/cpp/language/zero_initialization)。这是很常见的用法,不知道为什么你认为是不好的习惯呢?
    Tony042
        9
    Tony042  
       2021-04-30 09:51:11 +08:00
    @leimao 3 这个这个叫做 curiously recurring template pattern,CRTP,是用来实行静态多态的,实现和虚函数相似的效果,但避免虚函数带来的性能损失。
    lonewolfakela
        10
    lonewolfakela  
       2021-04-30 09:52:55 +08:00
    @Tony042 这是哪门子的 CRTP,Base 又不是模板类……
    Tony042
        11
    Tony042  
       2021-04-30 09:53:37 +08:00
    @lonewolfakela 学艺不精,sorry,sorry,没细看
    bestwaytowait
        12
    bestwaytowait  
       2021-04-30 09:53:52 +08:00
    @Tony042 不是啊,CRTP 是 template base
    Tony042
        13
    Tony042  
       2021-04-30 09:54:57 +08:00
    @lonewolfakela
    @bestwaytowait
    3 这个是不是就是一个模板偏特化?
    lonewolfakela
        14
    lonewolfakela  
       2021-04-30 09:56:12 +08:00
    @Tony042 是啊,2 楼说的很清楚了,因为成员 retValue 的类型不可能是 void,所以必须单独给 void 弄一个没有 retValue 的特化。
    lonewolfakela
        15
    lonewolfakela  
       2021-04-30 09:58:37 +08:00
    @3dwelcome retCode 那里不同的人对于到底用“int retCode = 0”更好还是“int retCode{}”更好可能还会有些争论,但是代码段 2 里那个“Type retValue {}”,因为不知道 Type 的类型是啥,所以还真就只能这么写了……
    greatbody
        16
    greatbody  
       2021-04-30 10:14:08 +08:00
    为啥现在人都说“小细节”而不说“细节”

    以后是不是要说“特别微小细微的细节”?
    bestwaytowait
        17
    bestwaytowait  
       2021-04-30 10:17:18 +08:00
    @greatbody 确实套娃了 =。= 哈哈哈哈
    yazoox
        18
    yazoox  
    OP
       2021-04-30 10:36:46 +08:00
    @leimao
    3 不是“多余”的?我如果需要使用 type 为 void 的,我直接使用 EventResult<void>不就可以了么?干嘛要单独写一行,特别 definition 一下?
    yazoox
        19
    yazoox  
    OP
       2021-04-30 10:39:33 +08:00
    @lonewolfakela
    “因为成员 retValue 的类型不可能是 void”
    为什么?模板的定义 Type retValue {}; 就是有可能是 void 啊?
    尤其是,再单独使用代码段 3,和直接使用代码 2 EventResult<void>不是一样的么?单独定义,retValue 的类型就可以为 void 了?
    yazoox
        20
    yazoox  
    OP
       2021-04-30 10:51:45 +08:00
    @leimao
    我看了一下你分享的链接,
    int retCode {} 是初始化,retCode 和 {} 中间可以添加“空格”,我以为必须连续...... int retCode{}
    nicebird
        21
    nicebird  
       2021-04-30 11:12:38 +08:00
    1. {}构造
    2. 和 1 一样
    3. 偏特化,void 类型不要 retValue
    zwy100e72
        22
    zwy100e72  
       2021-04-30 11:13:24 +08:00
    没有 3 的情况下你是无法使用 EventResult<void> 的,因为无法定义一个 void 类型的成员变量。参见 https://godbolt.org/z/dxn1h4h5T

    有 3 的情况下,EventResult<void> 的成员变量和 Base 一致,而其他类型的 EventResult<T> 有一个单独的 retValue 成员 https://godbolt.org/z/9TWfh1TGE
    lonewolfakela
        23
    lonewolfakela  
       2021-04-30 17:52:49 +08:00
    @yazoox “为什么?模板的定义 Type retValue {}; 就是有可能是 void 啊?”
    并不可能,因为变量的类型不能为 void 。
    mingl0280
        24
    mingl0280  
       2021-04-30 22:47:26 +08:00
    @leimao C++11 以上 POD/结构体变量初始化推荐使用{}。如果使用{0}只能初始化第一个,反而问题更大。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1780 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 16:32 · PVG 00:32 · LAX 09:32 · JFK 12:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.