【问题标题】:Conversion from class to identical class with different template types从类转换为具有不同模板类型的相同类
【发布时间】:2021-05-25 02:21:25
【问题描述】:

我有一个简单的类“vec2”。我希望这个类能够在类模板中存储双精度和双引用,甚至是 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 公开,但在类类型是引用时使成员私有?这将需要特定于何时返回 x 和 y 值的引用的方法。在参考版本中,它还需要没有可能影响参考的重载运算符方法。我稍微了解模板专业化,但还不足以真正实现它。

无论如何,这里的重点是找出如何获取vec2&lt;double&gt;类型的类,并将其转换为vec2&lt;double&amp;&gt;类型的类。

或者,反过来,取一个 vec2&lt;double&amp;&gt; 类型的类,并将其转换为 vec2&lt;double&gt; 类型的类。

这是我的简单 vec2 类-

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);
    }
};

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

【问题讨论】:

  • 听起来您的引用类型应该是完全不同的类模板。我很困惑vec2&lt;T&gt; 会有公共或私有数据成员以及不同的功能,具体取决于T 是什么。也许做一个vec2ref&lt;T&gt;?或者更好的是,摆脱它并使用const vec2&lt;T&gt;&amp;
  • @Kevin 我不认为它应该是一个不同的类......这看起来很丑陋。不能为不同的模板类型实现不同的方法吗?如果能够互换使用 vec2 和 vec2 那就太好了。我不认为 const vec2& 完全符合我的要求,因为我希望能够使用任何引用类型作为 x 和 y 成员,而 const vec2& 只允许vec2 的参考。如果我想使用 int x 和 int y 作为参考怎么办?不可能像使用 vec2 那样一步完成。

标签: c++ templates type-conversion template-specialization


【解决方案1】:

我做了更多的研究,并在模板专业化方面学到了很多东西。这是实现了我想要的一切的功能 vec2 类,以及一个“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) */

【讨论】:

    【解决方案2】:

    简化版。通过将字段设为私有,它们不能被修改。我没有尝试实现所有 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 和 vec2... 之间进行转换...这可能吗?
    猜你喜欢
    • 2019-12-18
    • 2018-12-28
    • 2011-07-30
    • 2014-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-11
    相关资源
    最近更新 更多