V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
killergun
V2EX  ›  问与答

为什么 c++开发总喜欢定义别名呢(typedef/#define)

  •  
  •   killergun · 2021-08-29 17:20:27 +08:00 · 2310 次点击
    这是一个创建于 1189 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不会仅为了写代码的时候 减少字符数?

    13 条回复    2021-08-30 08:06:35 +08:00
    BiteTheDust
        1
    BiteTheDust  
       2021-08-29 17:48:25 +08:00
    还有 using
    ipwx
        2
    ipwx  
       2021-08-29 17:56:04 +08:00
    1. 减少字符。
    2. 方便切换类型。

    有关切换类型:比如 typedef std::shared_ptr<XX>

    如果你后期想优化性能,把这个 shared_ptr 变成 memory_pool based smart_ptr (自己实现的),那你就明白这东西的好处了。

    3. 配合模板

    比如 template <typename Container>
    class XXX{
    typedef typename Container::value_type value_type;
    };
    ipwx
        3
    ipwx  
       2021-08-29 17:56:48 +08:00
    ps. 配合模板指的是,上面这个例子,我可以通过 XXX<std::vector<int>>::value_type 得到 int 了。
    fgwmlhdkkkw
        4
    fgwmlhdkkkw  
       2021-08-29 17:57:58 +08:00
    你是写 Java 的吧🧐
    Hconk
        5
    Hconk  
       2021-08-29 18:04:22 +08:00 via iPhone
    typedef 和 define 完全是两个东西,typedef 和 using 一样是在编译阶段生效,define 是在编译前的预处理阶段进行替换。

    先说 typedef 和 using,C++如果导出函数给别的语言最简单的方式就是提供 C 风格的接口,如果不用 typedef 起个别名看到一堆 void* ,uint32 很迷惑,这一点在 Windows API 里面多,这种情况下用不了 using 。

    还有你提到的为了减少变量类型长度,如果你用过 ITK 这种模版范式写过的库就知道,要是不起个别名的话每次定义个变量都很麻烦,这种情况下更推荐用 using 。定义模板的别名只能用 using 。

    #define 有些情况下没法替换,或者不用宏写起来很麻烦,具体可以看看这个 https://www.zhihu.com/question/30659549/answer/49956788
    ipwx
        6
    ipwx  
       2021-08-29 18:12:02 +08:00
    @Hconk 它后面两个例子我没有异议。不过第一个例子( LOOP_UNROLL_DOUBLE ):

    可以用

    template <typename Fn1, typename Fn2>
    inline void loopUnrolDouble(const Fn1& fn1, const Fn2& fn2) {
    ...
    }

    loopUnrollDouble(
    [&] () {
    ...
    },
    [&] () {
    ...
    }
    );

    开 -O3 应该会直接内联调用。当然我没真的反汇编看过,不过应当如此。所以 lambda 是好东西。
    ipwx
        7
    ipwx  
       2021-08-29 18:12:35 +08:00
    另外 const Fn1& const Fn2& 更现代一点可能会用 Fn1&& Fn2&& ,不过我觉得 -O3 就没去别了。
    QBugHunter
        8
    QBugHunter  
       2021-08-29 19:25:28 +08:00
    1.减少字符
    2.方便阅读代码
    zxCoder
        9
    zxCoder  
       2021-08-29 19:48:02 +08:00
    风格,千万不要拿别的语言那一套去看 c++
    TypeError
        10
    TypeError  
       2021-08-29 21:33:40 +08:00 via Android
    go 也推荐定义别名,增加可读性+方便替换扩展吧
    Caturra
        11
    Caturra  
       2021-08-29 22:01:12 +08:00
    我觉得,某种角度来看,STL 本身就是靠一堆别名堆砌而成的,

    以容器为例,一个容器如 vector<T, alloc> / list<T, alloc>内部有声明::value_type 、::reference 、::iterator 、blabla 等别名,这些主要是方便类型萃取,

    比如你写个通用的排序函数,接口就简单点 sort(Container&),表示对整个容器进行排序
    那么问题来了,怎么知道各种容器内的类型 T,最简单的萃取是通过 using T = typename Container::value_type 就能知道
    (当然你不用任何别名也可以,这个时候就需要自己写一个重载、Traits 类特化偏特化、SFINAE 等操作去支持,自找苦吃)

    各种迭代器 iterator 就更不用说了,实现 iterator 也是和容器一样规定了各种别名,并且有专门的萃取类型来辅助处理里面的别名,从而实现在模板的世界里为所欲为
    https://en.cppreference.com/w/cpp/iterator/iterator_traits

    也有一些设计 policy based 过于魔怔了,不得不用别名降低点阅读难度的例子,比如 gcc/hashtable.h,
    https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/hashtable.h
    (当前的版本)从 207 行开始就用了一堆的 using,你要是不用,那还真是整段代码没法看了

    如果你说 C++里面别名总是用#define,那我见识短,还没遇到过非用不可的情况
    mingl0280
        12
    mingl0280  
       2021-08-30 04:41:41 +08:00
    因为定义别名真的方便阅读……
    你看到一个 xxxx_TIMEOUT 的 define 就知道这个值是个超时了。
    不要随便把 magic number 放得程序里到处都是,这样能节约大量的阅读时间。
    还有一个用途是省空间。我之前写的一个回调的 using 大概长这样:
    ```
    using funcProto = int(unsigned char*, unsigned int, unsigned int, int&, int&);
    ```
    然后放在 std::function 里面就可以写成
    ```
    std::function<funcProto> some_func = reinterpret_cast<funcProto*>(GetProcAddress(lib_handle, "FunctionName"));
    ```
    这样。
    如果你直接用原始的话这一行会变成多长……
    iceheart
        13
    iceheart  
       2021-08-30 08:06:35 +08:00 via Android
    typedef 一般是模板类用的多,遵循依赖倒置原则,解耦外部依赖
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2562 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 03:49 · PVG 11:49 · LAX 19:49 · JFK 22:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.