C++ 虚方法部分模板特化
C++ Partial template specialization on virtual method
我有一个简单的基础 class 形状及其派生的 class 球。目的是在标量类型和维度上具有通用性,因此使用模板。
#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> circle{{0.2f,0.3f}, 4.0f};
std::cout << circle.volume() << std::endl;
}
我想使用部分模板专业化来根据维度计算体积。该代码有效,但如果我必须专门针对另一种类型(例如 double)(代码将相同),则很麻烦。
我知道我不能对虚拟方法进行部分模板特化,但是当我使用上面的注释代码时,出现以下错误而不是 错误:模板可能不是 'virtual':
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> {
我并没有真正得到这个错误,如何避免它以及如何优雅地获得这种通用性?
几乎总是,如果你需要函数模板部分特化,你可以使用"delegate to class"技巧:
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;
我有一个简单的基础 class 形状及其派生的 class 球。目的是在标量类型和维度上具有通用性,因此使用模板。
#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> circle{{0.2f,0.3f}, 4.0f};
std::cout << circle.volume() << std::endl;
}
我想使用部分模板专业化来根据维度计算体积。该代码有效,但如果我必须专门针对另一种类型(例如 double)(代码将相同),则很麻烦。
我知道我不能对虚拟方法进行部分模板特化,但是当我使用上面的注释代码时,出现以下错误而不是 错误:模板可能不是 'virtual':
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> {
我并没有真正得到这个错误,如何避免它以及如何优雅地获得这种通用性?
几乎总是,如果你需要函数模板部分特化,你可以使用"delegate to class"技巧:
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;