如何从作为特化的派生类访问基类模板参数?
在派生类中访问基类模板参数的替代方案(无需
static constexpr) C++不支持模板成员函数的偏特化,我打算用类模板继承来规避这个问题——派生类继承基类时,固定部分模板参数,剩余参数保留为派生类的模板参数,示例代码如下:
template <typename X, typename Y, typename Z> class Base{}; template <typename Z> class Derived : public Base<int, int, Z>{};
现在我想在派生类内部访问继承时指定的基类模板参数(比如上面的int、int)。目前的做法是在基类里把这些参数定义为static constexpr成员,让派生类直接访问,但我想知道有没有不用显式定义static constexpr的方法。以下是我当前的实现,希望能改进:
#include <cstdint> #include <iostream> template<std::size_t Dimension, std::size_t Size, typename Real> class BaseDistribution { public: static constexpr std::size_t dim_ = Dimension; static constexpr std::size_t size_ = Size; }; template<typename Real> class DerivedDistribution : public BaseDistribution<2, 9, Real> { public: void print_dimension() { std::cout << "Dimension: " << this->dim_ << std::endl; } void print_size() { std::cout << "Size: " << this->size_ << std::endl; } }; int main() { DerivedDistribution<double> foo; foo.print_dimension(); foo.print_size(); return 0; }
方法1:给基类添加嵌套类型包装器
用std::integral_constant把模板参数包装成嵌套类型,代替static constexpr成员变量,派生类通过类型的value成员访问参数值:
#include <cstdint> #include <iostream> #include <type_traits> template<std::size_t Dimension, std::size_t Size, typename Real> class BaseDistribution { public: // 用integral_constant包装模板参数,作为嵌套类型 using dimension = std::integral_constant<std::size_t, Dimension>; using size = std::integral_constant<std::size_t, Size>; }; template<typename Real> class DerivedDistribution : public BaseDistribution<2, 9, Real> { public: void print_dimension() { // 通过嵌套类型的value成员获取参数值 std::cout << "Dimension: " << dimension::value << std::endl; } void print_size() { std::cout << "Size: " << size::value << std::endl; } }; int main() { DerivedDistribution<double> foo; foo.print_dimension(); foo.print_size(); return 0; }
这种方式不需要定义static constexpr变量,而是利用类型系统传递参数,风格更贴近C++模板编程的习惯。
方法2:用外部模板萃取器提取参数
如果不能修改基类,可以写一个外部萃取器模板,专门提取基类的模板参数:
#include <cstdint> #include <iostream> template<std::size_t Dimension, std::size_t Size, typename Real> class BaseDistribution { // 原基类,无需修改 }; // 萃取器模板,用于提取BaseDistribution的模板参数 template<typename Dist> struct DistributionTraits; // 针对BaseDistribution的特化版本 template<std::size_t Dim, std::size_t S, typename R> struct DistributionTraits<BaseDistribution<Dim, S, R>> { static constexpr std::size_t dimension = Dim; static constexpr std::size_t size = S; using real_type = R; }; template<typename Real> class DerivedDistribution : public BaseDistribution<2, 9, Real> { // 用别名简化基类类型引用 using Base = BaseDistribution<2, 9, Real>; public: void print_dimension() { // 通过萃取器获取基类的模板参数 std::cout << "Dimension: " << DistributionTraits<Base>::dimension << std::endl; } void print_size() { std::cout << "Size: " << DistributionTraits<Base>::size << std::endl; } }; int main() { DerivedDistribution<double> foo; foo.print_dimension(); foo.print_size(); return 0; }
萃取器的优势是不需要修改原有基类代码,通过模板特化实现参数提取,适合基类无法修改的场景。
方法3:派生类直接复用固定参数
如果派生类继承时指定的基类参数是固定值(比如示例中的2和9),可以直接在派生类中定义对应的常量,完全不依赖基类:
#include <cstdint> #include <iostream> template<std::size_t Dimension, std::size_t Size, typename Real> class BaseDistribution { // 原基类,无需任何额外成员 }; template<typename Real> class DerivedDistribution : public BaseDistribution<2, 9, Real> { public: // 直接在派生类中定义固定参数 static constexpr std::size_t dim_ = 2; static constexpr std::size_t size_ = 9; void print_dimension() { std::cout << "Dimension: " << dim_ << std::endl; } void print_size() { std::cout << "Size: " << size_ << std::endl; } }; int main() { DerivedDistribution<double> foo; foo.print_dimension(); foo.print_size(); return 0; }
这种方式最简单直接,但耦合性较高——如果基类的参数需要修改,派生类也要同步修改,适合参数长期固定的场景。
内容的提问来源于stack exchange,提问作者user6671981
相关产品推荐
相关产品推荐

