虚拟方法的 C++ 部分模板特化
Posted
技术标签:
【中文标题】虚拟方法的 C++ 部分模板特化【英文标题】:C++ Partial template specialization on virtual method 【发布时间】:2015-03-18 09:13:59 【问题描述】:我有一个简单的基类 Shape 及其派生类 Ball。目的是在标量类型和维度上具有通用性,从而使用模板。
#include <iostream>
#include <array>
#include <cmath>
template<typename T, std::size_t DIM>
class Shape
public:
Shape(std::array<T,DIM> base_point) : base_point_(base_point)
virtual T volume() const = 0;
protected:
std::array<T,DIM> base_point_;
;
template<typename T, std::size_t DIM>
class Ball : public Shape<T,DIM>
public:
Ball(std::array<T,DIM> base_point, T radius) : Shape<T,DIM>(base_point), radius_(radius)
virtual T volume() const;
private:
T radius_;
;
// Cannot use the generic code below because of Template may not be 'virtual' ?
// template<typename T>
// T Ball<T,2>::volume() const return M_PI * radius_ * radius_;
template<>
float Ball<float,2>::volume() const return M_PI * radius_ * radius_;
// template<typename T>
// T Ball<T,3>::volume() const return 4/3 * M_PI * radius_ * radius_ * radius_;
template<>
float Ball<float,3>::volume() const return 4/3 * M_PI * radius_ * radius_ * radius_;
int main()
Ball<float,2> circle0.2f,0.3f, 4.0f;
std::cout << circle.volume() << std::endl;
我想使用部分模板专业化来根据维度计算体积。该代码可以工作,但如果我必须专门针对另一种类型(例如双精度),代码会很麻烦(代码相同)。
我知道我不能对虚拟方法进行部分模板特化,但是当我使用上面的注释代码时,我有以下错误而不是 错误:模板可能不是“虚拟”:
shape_generic_naive.cpp:24:25: error: invalid use of incomplete type ‘class Sphere<T, 2ul>’
T Sphere<T,2>::volume() const return M_PI * radius_ * radius_;
^
shape_generic_naive.cpp:15:7: error: declaration of ‘class Sphere<T, 2ul>’
class Sphere : public Shape<T,DIM>
我并没有真正得到这个错误,如何避免它以及有什么方法可以优雅地获得这种通用性?
【问题讨论】:
【参考方案1】:几乎总是,如果您需要函数模板部分特化,您可以使用“委托给类”技巧:
template <class T, std::size_t DIM>
struct BallVolume;
template <class T>
struct BallVolume<T, 2>
static T compute(T radius) return M_PI * radius * radius;
;
template <class T>
struct BallVolume<T, 3>
static T compute(T radius) return 4.0/3.0 * M_PI * radius * radius * radius;
;
template<typename T, std::size_t DIM>
class Ball : public Shape<T,DIM>
public:
Ball(std::array<T,DIM> base_point, T radius) : Shape<T,DIM>(base_point), radius_(radius)
virtual T volume() const return BallVolume<T, DIM>::compute(radius_);
private:
T radius_;
;
请注意,您的 3D 体积公式不正确:4/3
是 1
,因为它是整数除法。
另外,为了保持真正的类型中立,您应该将常量转换为T
:
return static_cast<T>(M_PI) * radius * radius;
return 4 / static_cast<T>(3.0) * static_cast<T>(M_PI) * radius * radius * radius;
【讨论】:
BallVolume
应该在Ball
之前声明,或者后面定义的volume
成员函数
@PiotrS。或者读者在阅读答案时运用常识。我也没有#include
std::size_t
的标题。但为了以防万一,我把顺序颠倒了。
@coincoin 4.0
的类型为 double
。如果你用T = float
实例化它,你会得到一个(合理的)编译器警告。
@coincoin 这看起来真的是一个单独的问题。但考虑到您正在尝试部分特化函数模板Ball::volume
,并且不允许函数模板的部分特化。
哦,我明白了,谢谢你的观点:只允许全功能模板专业化。那我会坚持你的解决方案。以上是关于虚拟方法的 C++ 部分模板特化的主要内容,如果未能解决你的问题,请参考以下文章
C++模板详解:泛型编程模板原理非类型模板参数模板特化分离编译