请教一个 C++模板问题 (≥C++17) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
justou
V2EX    C++

请教一个 C++模板问题 (≥C++17)

  •  
  •   justou 2022-04-16 11:40:16 +08:00 2745 次点击
    这是一个创建于 1280 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有这样一些我无法修改的类(简化一下):

    struct SomeComplexBase{ static inline int data_1 = 1; static inline int data_2 = 2; // ... // static inline int data_n = N; }; struct ClassA: SomeComplexBase{ }; struct ClassB { typedef SomeComplexBase Base; };  

    我自己实现的一个模板函数

    void func(){ /* * 接收 ClassA, ClassB 类型 * 有没有什么模板技巧可以消除 ClassA::data_n, ClassB::Base::data_n 这种不一致的成员访问方式? * 比如, 可以这样访问成员 NewType::data_n? * * if constexpr(std::is_same_v(T, ClassB))的方式纵然可行, * 但是两个分支代码都是一样的, 仅有以上提到的访问成员不一致的区别, 跟写两个完全重复的模板函数一样. * */ } 

    谢谢各位

    10 条回复    2022-04-16 21:49:46 +08:00
    ink19
        1
    ink19  
       2022-04-16 11:56:53 +08:00   2
    ```C++
    #include <iostream>

    struct SomeComplexBase{
    static inline int data_1 = 1;
    static inline int data_2 = 2;
    // ...
    // static inline int data_n = N;
    };

    struct ClassA: SomeComplexBase{

    };

    struct ClassB {
    typedef SomeComplexBase Base;
    };

    template<typename T, bool>
    struct DeWapper;

    template<typename T>
    struct DeWapper<T, false> {
    typedef typename T::Base Base;
    };

    template<typename T>
    struct DeWapper<T, true> {
    typedef T Base;
    };

    template<typename T>
    struct De {
    typedef typename DeWapper<T, std::is_base_of_v<SomeComplexBase, T>>::Base Base;
    };

    template<typename T>
    int func() {
    return De<T>::Base::data_1;
    }

    int main() {
    std::cout << func<ClassA>() << std::endl;
    std::cout << func<ClassB>() << std::endl;
    }
    ```
    yelite
        2
    yelite  
       2022-04-16 11:58:59 +08:00 via iPhone   1
    能不能对于每个 data_n 写一个 template 的 getter function ,然后对这两个类 specialize
    TuneG
        3
    TuneG  
       2022-04-16 11:59:01 +08:00 via iPhone   1
    这个,使用 typedef 就会有这种问题,如果不能改成 alias declaration ,那的确没有好方法,标准库中 type trait 也是有这种历史代码使用嵌套在模版化的 struct 里的 typedef 实现的,所以存在两套调用,对应的每种都有对应的别名模版调用方式,例如 std::remove_const<T>::type 的别名模版调用 std::remove_const_t<T>,为啥标准库不统一起来,估计也没什么好方法,不如不统一
    ink19
        4
    ink19  
       2022-04-16 12:01:28 +08:00   1
    @ink19 应该是这个意思吧?直接加一层封装就好了,感觉函数式编程就是这样,功能都能想办法实现,就是加封装的层数问题
    justou
        5
    justou  
    OP
       2022-04-16 12:14:18 +08:00
    @ink19 是这个意思, 我就知道肯定有办法的, 谢谢~
    GeruzoniAnsasu
        6
    GeruzoniAnsasu  
       2022-04-16 12:23:33 +08:00   1
    https://godbolt.org/z/vq6hM4534

    定义一个 trait 类,其中有一个类型成员 BaseType:
    当 T::Base 存在时 using BaseType= T::base
    当 T 继承自 SomeBase 时 using BaseType=SomeBase

    另外介绍一下这个站:
    https://cpppatterns.com/patterns/function-template-sfinae.html
    https://cpppatterns.com/patterns/class-template-sfinae.html


    我几乎每回重新写 trait 都要来查一下。。
    justou
        7
    justou  
    OP
       2022-04-16 12:28:15 +08:00
    @GeruzoniAnsasu 也是好办法, 谢谢推荐
    dangyuluo
        8
    dangyuluo  
       2022-04-16 12:56:13 +08:00
    虽然用 Traits 可以解决这个问题,但是从另一个角度想,func 似乎不应该同时接受 classA 和 classB ,毕竟一个是 IS-A, 一个是 HAS-A (借用继承的思路)
    lujunliang
        9
    lujunliang  
       2022-04-16 16:55:09 +08:00
    @GeruzoniAnsasu 请教一下,这里 constexpr _helper 的函数体在什么情况下允许为空的呢?
    GeruzoniAnsasu
        10
    GeruzoniAnsasu  
       2022-04-16 21:49:46 +08:00
    @lujunliang 模板只有在用到的时候才会实例化,实例化前被剔除掉的话根本不会进入语法检查阶段。 trait 类的所有成员最终只会留下 BaseType**推导结果** 的定义。在这个类里写一个 int a(){return "X";} 编译器都是不管的。所以只把声明留下来不要函数体也可以,反正最后编译器不会去检查这个函数的定义在哪里,只是用声明计算类型而已。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1112 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 18:12 PVG 02:12 LAX 11:12 JFK 14:12
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86