有这样一些我无法修改的类(简化一下):
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))的方式纵然可行,
* 但是两个分支代码都是一样的, 仅有以上提到的访问成员不一致的区别, 跟写两个完全重复的模板函数一样.
* */
}
谢谢各位
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; } ``` |
2
yelite 2022-04-16 11:58:59 +08:00 via iPhone 1
能不能对于每个 data_n 写一个 template 的 getter function ,然后对这两个类 specialize
|
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>,为啥标准库不统一起来,估计也没什么好方法,不如不统一
|
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 都要来查一下。。 |
7
justou OP @GeruzoniAnsasu 也是好办法, 谢谢推荐
|
8
dangyuluo 2022-04-16 12:56:13 +08:00
虽然用 Traits 可以解决这个问题,但是从另一个角度想,func 似乎不应该同时接受 classA 和 classB ,毕竟一个是 IS-A, 一个是 HAS-A (借用继承的思路)
|
9
lujunliang 2022-04-16 16:55:09 +08:00
@GeruzoniAnsasu 请教一下,这里 constexpr _helper 的函数体在什么情况下允许为空的呢?
|
10
GeruzoniAnsasu 2022-04-16 21:49:46 +08:00
@lujunliang 模板只有在用到的时候才会实例化,实例化前被剔除掉的话根本不会进入语法检查阶段。 trait 类的所有成员最终只会留下 BaseType**推导结果** 的定义。在这个类里写一个 int a(){return "X";} 编译器都是不管的。所以只把声明留下来不要函数体也可以,反正最后编译器不会去检查这个函数的定义在哪里,只是用声明计算类型而已。
|