hellomyprogram 发表于 2023-10-15 20:12:18

C++ 模板类特化中的变量问题

我有这一段代码:
#include <array>
template <unsigned short dimensions>
class Vector
{
        public:
                static const unsigned short dimension = dimensions;
                std::array<double, dimensions> values;
                Vector() = default;
                Vector(const Vector &) = default;
                Vector(Vector &&) = default;
                Vector(std::array<double, dimensions> values)
                {
                        this->values = values;
                };
                Vector<dimensions> & operator=(const Vector<dimensions> &) = default;
                Vector<dimensions> operator+(const Vector<dimensions> &other) const
                {
                        Vector<dimensions> result;
                        for (unsigned short index = 0; index < dimensions; index++)
                        {
                                result.values = this->values + other.values;
                        };
                        return result;
                };
                Vector<dimensions> operator+(const double other) const
                {
                        Vector<dimensions> result;
                        for (unsigned short index = 0; index < dimensions; index++)
                        {
                                result.values = this->values + other;
                        };
                        return result;
                };
                Vector<dimensions> operator-() const
                {
                        Vector<dimensions> result;
                        for (unsigned short index = 0; index < dimensions; index++)
                        {
                                result.values = -this->values;
                        };
                        return result;
                };
                Vector<dimensions> operator-(const Vector<dimensions> &other) const
                {
                        return (*this) + -other;
                };
                Vector<dimensions> operator-(const double other) const
                {
                        return *this + -other;
                };
                Vector<dimensions> operator*(const double other) const
                {
                        Vector<dimensions> result;
                        for (unsigned short index = 0; index < dimensions; index++)
                        {
                                result.values = this->values * other;
                        };
                        return result;
                };
                Vector<dimensions> operator/(const double other) const
                {
                        return *this * (1.0 / other);
                };
                double dot(const Vector<dimensions> &other) const
                {
                        double result = 0;
                        for (unsigned short index = 0; index < dimensions; index++)
                        {
                                result += this->values * other.values;
                        };
                        return result;
                };
                double length() const
                {
                        return sqrt(this->dot(*this));
                };
                Vector<dimensions> length(const int scale) const
                {
                        return *this / (this->length() / scale);
                };
                double angle(const Vector<dimensions> &other) const
                {
                        return acos(this->dot(other) / (this->length() * other.length()));
                };
};

template <>
class Vector<3>
{
        public:
                Vector<3> operator*(const Vector<3> &other) const
                {
                        Vector<3> result;
                        for (unsigned short index = 0; index < 3; index++)
                        {
                                result.values = this->values[(index + 1) % 3] * other.values[(index + 2) % 3] - this->values[(index + 2) % 3] * other.values[(index + 1) % 3];
                        };
                        return result;
                };
};
我对这个 Vector 进行特化,使其能够完成仅提供三维支持的叉乘,但是编译器报错说在特化中 'const class Vector<3>' has no member named 'values' ,难道特化不保有模板的函数和变量吗?如果不保有,那么怎么修改才能做到减少代码冗余;如果保有,那么这里为什么会报错,又怎么解决?

陶远航 发表于 2023-10-15 20:12:55

在C++中,模板特化并不保留原模板的成员函数和变量。当你为模板类进行特化时,你实际上是在为特定的模板参数创建一个全新的类定义。这就是为什么在你的特化版本的 Vector<3> 中,编译器无法找到 values 成员的原因。

如果你希望在特化版本中保留一些通用的成员和函数,你可以考虑使用模板类的继承。例如,你可以创建一个基础的 VectorBase 类,然后让 Vector 继承自 VectorBase。这样,你就可以在 VectorBase 中定义通用的成员和函数,然后在 Vector 的特化版本中添加或覆盖特定的成员和函数。

以下是一个简单的示例:

template <unsigned short dimensions>
class VectorBase {
public:
    static const unsigned short dimension = dimensions;
    std::array<double, dimensions> values;
    // ... 其他通用的成员和函数 ...
};

template <unsigned short dimensions>
class Vector : public VectorBase<dimensions> {
    // ... 特定的成员和函数 ...
};

template <>
class Vector<3> : public VectorBase<3> {
public:
    Vector<3> operator*(const Vector<3> &other) const {
      Vector<3> result;
      for (unsigned short index = 0; index < 3; index++) {
            result.values = this->values[(index + 1) % 3] * other.values[(index + 2) % 3] - this->values[(index + 2) % 3] * other.values[(index + 1) % 3];
      };
      return result;
    };
};


这样,Vector<3> 就可以访问 VectorBase<3> 中定义的 values 成员了。同时,你也可以在 Vector<3> 中添加或覆盖特定的成员和函数,以实现三维向量的特殊操作。
请注意,本回答来自GPT-4
如果问题已经解决,请设置最佳答案

isdkz 发表于 2023-10-15 20:13:44

在模板类特化中,只有特化的部分会被编译器处理,其他部分将被忽略。因此,在 Vector<3> 的特化中,只有特化的部分会被编译器处理,而原始模板中的成员变量 values 并不会被保留。

要解决这个问题,可以使用继承来避免代码冗余。首先,将原始模板类中的所有成员函数和变量都放在一个基类中,然后在特化中继承这个基类并添加新的成员函数和变量。这样,特化中就可以使用基类中的成员变量 values 了。

以下是修改后的代码:

#include <array>
#include <cmath>

template <unsigned short dimensions>
class VectorBase
{
public:
    static const unsigned short dimension = dimensions;
    std::array<double, dimensions> values;
    VectorBase() = default;
    VectorBase(const VectorBase &) = default;
    VectorBase(VectorBase &&) = default;
    VectorBase(std::array<double, dimensions> values)
    {
      this->values = values;
    };
    VectorBase<dimensions> &operator=(const VectorBase<dimensions> &) = default;
    VectorBase<dimensions> operator+(const VectorBase<dimensions> &other) const
    {
      VectorBase<dimensions> result;
      for (unsigned short index = 0; index < dimensions; index++)
      {
            result.values = this->values + other.values;
      };
      return result;
    };
    VectorBase<dimensions> operator+(const double other) const
    {
      VectorBase<dimensions> result;
      for (unsigned short index = 0; index < dimensions; index++)
      {
            result.values = this->values + other;
      };
      return result;
    };
    VectorBase<dimensions> operator-() const
    {
      VectorBase<dimensions> result;
      for (unsigned short index = 0; index < dimensions; index++)
      {
            result.values = -this->values;
      };
      return result;
    };
    VectorBase<dimensions> operator-(const VectorBase<dimensions> &other) const
    {
      return (*this) + -other;
    };
    VectorBase<dimensions> operator-(const double other) const
    {
      return *this + -other;
    };
    VectorBase<dimensions> operator*(const double other) const
    {
      VectorBase<dimensions> result;
      for (unsigned short index = 0; index < dimensions; index++)
      {
            result.values = this->values * other;
      };
      return result;
    };
    VectorBase<dimensions> operator/(const double other) const
    {
      return *this * (1.0 / other);
    };
    double dot(const VectorBase<dimensions> &other) const
    {
      double result = 0;
      for (unsigned short index = 0; index < dimensions; index++)
      {
            result += this->values * other.values;
      };
      return result;
    };
    double length() const
    {
      return std::sqrt(this->dot(*this));
    };
    VectorBase<dimensions> length(const int scale) const
    {
      return *this / (this->length() / scale);
    };
    double angle(const VectorBase<dimensions> &other) const
    {
      return std::acos(this->dot(other) / (this->length() * other.length()));
    };
};

template <unsigned short dimensions>
class Vector : public VectorBase<dimensions>
{
public:
    using VectorBase<dimensions>::VectorBase;
};

template <>
class Vector<3> : public VectorBase<3>
{
public:
    Vector<3> operator*(const Vector<3> &other) const
    {
      Vector<3> result;
      for (unsigned short index = 0; index < 3; index++)
      {
            result.values = this->values[(index + 1) % 3] * other.values[(index + 2) % 3] - this->values[(index + 2) % 3] * other.values[(index + 1) % 3];
      };
      return result;
    };
};


在这个修改后的代码中,VectorBase 类包含了原始模板中的所有成员函数和变量,Vector 类和 Vector<3> 类继承了 VectorBase 类并添加了新的成员函数。这样,Vector<3> 就可以使用基类中的成员变量 values 了。

希望这个解决方案能够帮到你!
页: [1]
查看完整版本: C++ 模板类特化中的变量问题