如何不使用typedef、别名及using获取基类模板参数类型?
不使用typedef/别名/using获取基类模板参数类型的方案
可以利用基类中doSomething()纯虚函数的返回类型进行编译期推导,完全不需要在A中额外定义using Type=T,也能拿到对应的模板参数类型。
简洁实现(利用decltype推导)
直接通过decltype结合std::declval提取doSomething()的返回类型,这就是A的模板参数类型:
#include <iostream> #include <utility> template <class T> class A { public: virtual T doSomething() const = 0; }; template <class T> class B : public T { // 推导基类A的模板参数类型 using Type = decltype(std::declval<const T&>().doSomething()); public: Type doSomething() const override { return 0; } Type value; }; class C : public A<double> { public: }; class D : public A<int> { public: }; int main() { B<C> b1; B<D> b2; std::cout << b1.doSomething() << "\n"; std::cout << b2.doSomething() << "\n"; }
std::declval<const T&>()用来在编译期模拟一个const T类型的引用,无需实际构造对象。decltype会提取doSomething()调用表达式的类型,也就是A的模板参数T。
完全不使用using的写法
如果要求连B中的using都不能用,直接在需要类型的位置写decltype表达式即可:
template <class T> class B : public T { public: decltype(std::declval<const T&>().doSomething()) doSomething() const override { return 0; } decltype(std::declval<const T&>().doSomething()) value; };
备选方案:模板特化提取类型
也可以通过模板特化结合SFINAE来检测派生类的基类参数,不过这种写法更繁琐,适合更复杂的场景:
#include <iostream> #include <type_traits> template <class T> class A { public: virtual T doSomething() const = 0; }; // 辅助模板:检测类型是否继承自A<V>并提取V template <typename U> struct ExtractAArg { private: // 匹配继承自A<V>的类型 template <typename V> static V test(const A<V>*); // 默认匹配 static void test(...); public: using Type = decltype(test(static_cast<const U*>(nullptr))); }; template <class T> class B : public T { using Type = typename ExtractAArg<T>::Type; public: Type doSomething() const override { return 0; } Type value; }; class C : public A<double> { public: }; class D : public A<int> { public: }; int main() { B<C> b1; B<D> b2; std::cout << b1.doSomething() << "\n"; std::cout << b2.doSomething() << "\n"; }
内容的提问来源于stack exchange,提问作者Miroslav Krajcir
相关产品推荐
相关产品推荐

