使用不同的模板类型从 class 转换为相同的 class

Conversion from class to identical class with different template types

我有简单的class“vec2”。我希望 class 能够在 class 模板中存储双精度和双精度引用,甚至是 int 和 int 引用。这是所需的行为-

vec2<double> base(5, 5);  //normal vec2
vec2<double&> reference(base.x, base.y);  //vec2 reference to vec2 "base"
vec2<double> third;

base.x++; //base.x equals 6, this also changes reference.x to 6;
third = reference; //conversion between vec2<double> and vec2<double&>

我还想修改 vec2 的引用实例是不可能的,除非通过更改它引用的变量 - 所以下面的代码会产生编译器错误

vec2<double&> reference(base.x, base.y);  //vec2 reference to vec2 "base"
reference.x = 5; //undesired behaviour

有没有办法让成员 x 和 y public 在处理非引用 class 类型时,但在 class 类型是引用时是私有的?这将需要特定于何时将 return x 和 y 的值作为参考的方法。在引用版本中,它还需要没有可能影响引用的重载运算符方法。我对模板特化略有了解,但还不足以真正实现它。

无论如何,本文的要点是找出如何获取 vec2<double> 类型的 class,并将其转换为 vec2<double&> 类型的 class .

或者,相反地,将 vec2<double&> 类型的 class 转换为 vec2<double>.

类型的 class

这是我的简单 vec2 class-

template <class T> class vec2{
public:
    vec2(){
        x = 0;
        y = 0;
    }
    vec2(T X, T Y){
        x = X;
        y = Y;
    }
    void normalize(){   //this function should inaccesable to any "reference version" of vec2
        *this /= magnitude();
    }
    void rotate(double radians, vec2 center){   //this should also be inaccesable to reference versions
        vec2 ogPts = *this -= center;
        x = ogPts.x*cos(radians) - ogPts.y*sin(radians);
        y = ogPts.y*cos(radians) + ogPts.x*sin(radians);
        *this += center;
    }
    double magnitude() const{
        return sqrt(x * x + y * y);  //this should be available to both
    }
    T x;
    T y;
    vec2 operator+(const vec2 &v) const{  //available to both
        return vec2(x+v.x, y+v.y);
    }
    vec2 operator-(const vec2 &v) const{ //available to both
        return vec2(x-v.x, y-v.y);
    }
    vec2 operator*(const vec2 &v) const{ //available to both

        return vec2(x*v.x, y*v.y);
    }
    vec2 operator*(T v) const{ //available to both, but should work even if v is not a reference variable and T is a reference
        return vec2(x*v, y*v);
    }
    vec2 operator/(T v) const{ //available to both, but should work even if v is not a reference variable and T is a reference
        return vec2(x/v, y/v);
    }
    vec2 operator+=(const vec2 &v){ //inaccesable to reference versions of the class
        x += v.x;
        y += v.y;
        return *this;
    }
    vec2 operator-=(const vec2 &v){ //inaccesable to reference versions
        x -= v.x;
        y -= v.y;
        return *this;
    }
    vec2 operator*=(const vec2 &v){ //inaccesable to reference versions
        x *= v.x;
        y *= v.y;
        return *this;
    }
    vec2 operator*=(T v){ //inaccesable to reference versions
        x *= v;
        y *= v;
        return *this;
    }
    vec2 operator/=(T v){ //inaccesable to reference versions
        x /= v;
        y /= v;
        return *this;
    }
    bool operator==(const vec2 &v) const{ //this should be available to both
        return (v.x == x && v.y == y);
    }
    bool operator!=(const vec2 &v) const{ //this should be available to both
        return (v.x != x || v.y != y);
    }
};

非常感谢任何帮助!我没有太多使用模板,事实上,我昨天才开始!提前感谢您的宝贵时间!

简化版。通过将这些字段设为私有,它们就不能被修改。我没有尝试实现所有 operator= 方法,但您的代码应该可以工作。

我不太确定你的困惑在哪里。扫描没有发现任何问题,除了我将这些字段设为私有以便没有人可以触摸它们,并改为添加访问器方法。

#include <iostream>

using namespace std;

template <class T>
class MyClass {
private:
    T x;
    T y;

public:
    MyClass(T _x, T _y) : x(_x), y(_y) {}

    T getX() const { return x; }
    T getY() const { return y; }
};

int main(int, char **) {
    double x {1.0};
    double y {2.5};

    MyClass<double> withDouble(x, y);
    MyClass<double &> withRef{x, y};

    cout << "withDouble: " << withDouble.getX() << ", " << withDouble.getY() << endl;
    cout << "withRef: " << withRef.getX() << ", " << withRef.getY() << endl;

    x = 3.9;
    y = 5.4;
    cout << "withRef: " << withRef.getX() << ", " << withRef.getY() << endl;
}

我做了更多的研究,并设法在模板专业化方面学到了很多东西。这是功能性的 vec2 class,它实现了我想要的一切,加上一个“perpindiculate”函数和一个“swap”函数-

template <class T> class vec2{
public:
    vec2(){
        x = 0;
        y = 0;
    }
    vec2(T X, T Y){
        x = X;
        y = Y;
    }
    operator vec2<T&>(){
        return vec2<T&>(x, y);
    }
    void swap(){
        std::swap(x, y);
    }
    void perpindiculate(){
        std::swap(x, y);
        y = -y;
    }
    void normalize(){
        *this /= magnitude();
    }
    void rotate(double radians, vec2 center){
        vec2 ogPts = *this -= center;
        x = ogPts.x*cos(radians) - ogPts.y*sin(radians);
        y = ogPts.y*cos(radians) + ogPts.x*sin(radians);
        *this += center;
    }
    double magnitude() const{
        return sqrt(x * x + y * y);
    }
    vec2 operator+(const vec2 &v) const{
        return vec2(x+v.x, y+v.y);
    }
    vec2 operator-(const vec2 &v) const{
        return vec2(x-v.x, y-v.y);
    }
    vec2 operator*(const vec2 &v) const{
        return vec2(x*v.x, y*v.y);
    }
    vec2 operator*(T v) const{
        return vec2(x*v, y*v);
    }
    vec2 operator/(T v) const{
        return vec2(x/v, y/v);
    }
    vec2 operator+=(const vec2 &v){
        x += v.x;
        y += v.y;
        return *this;
    }
    vec2 operator-=(const vec2 &v){
        x -= v.x;
        y -= v.y;
        return *this;
    }
    vec2 operator*=(const vec2 &v){
        x *= v.x;
        y *= v.y;
        return *this;
    }
    vec2 operator*=(T v){
        x *= v;
        y *= v;
        return *this;
    }
    vec2 operator/=(T v){
        x /= v;
        y /= v;
        return *this;
    }
    bool operator==(const vec2 &v) const{
        return (v.x == x && v.y == y);
    }
    bool operator!=(const vec2 &v) const{
        return (v.x != x || v.y != y);
    }
    T x;
    T y;
};

template<class T>
class vec2<T&>{
public:
    vec2(T& X, T& Y) : x{X}, y{Y} {}
    operator vec2<T>(){
        return vec2<T>(x, y);
    }
    vec2<T> swap() const{
        return vec2<T>(y, x);
    }
    vec2<T> perpindiculate() const{
        return vec2<T>(-y, x);
    }
    vec2<T> normalize() const{
        return *this / magnitude();
    }
    vec2<T> rotate(double radians, vec2 center) const{
        return vec2<T>(x*cos(radians) - y*sin(radians), y*cos(radians) + x*sin(radians));
    }
    double magnitude() const{
        return sqrt(x * x + y * y);
    }
    vec2 operator+(const vec2 &v) const{
        return vec2(x+v.x, y+v.y);
    }
    vec2 operator-(const vec2 &v) const{
        return vec2(x-v.x, y-v.y);
    }
    vec2 operator*(const vec2 &v) const{
        return vec2(x*v.x, y*v.y);
    }
    vec2 operator*(T& v) const{
        return vec2(x*v, y*v);
    }
    vec2 operator/(T& v) const{
        return vec2(x/v, y/v);
    }
    bool operator==(const vec2 &v) const{
        return (v.x == x && v.y == y);
    }
    bool operator!=(const vec2 &v) const{
        return (v.x != x || v.y != y);
    }
    T getx(){
        return x;
    }
    T gety(){
        return y;
    }
private:
    T& x;
    T& y;
};

这是一个工作的例子-

double x = 5;  //create future reference variables
double y = 3;
vec2<double&> vecref(x, y); //create vec2 referring to x and y
x = 7; //change x and y values, also changing vecref's values as well
y = 8;
vec2<double> vecOffRef = vecref; //conversion from a reference vec to a normal one
vec2<double&> vecOffRefref = vecOffRef; //conversion from a normal vec to a reference one
vecOffRef.normalize(); //normalize vec, also normalizing vecOffRefref

/* x equals 7, y = 8
   vecRef equals (7, 8)
   vecOffRef equals (0.6585, .7525)
   vecOffRefRef equals (0.6585, .7525) */