【问题标题】:Overloading Operators in Templates Classes with Friend Operators使用友元运算符重载模板类中的运算符
【发布时间】:2016-11-10 06:10:56
【问题描述】:

考虑下面这个类Operand:它是一个非常直接的类,因为它接受一个参数并定义了一堆重载运算符,为了简化测试这个类,我选择使用float 类型,因为那里是除法运算符。如果您注意到某些操作员被定义为朋友,以便能够在他们的代码中执行此操作:

编辑 有人在cmets里问什么

inline friend Operand Operand::operator+( const Operand& A, const Operand B ) 

是什么意思?它是一个重载运算符,但由于已经为类本身定义了一个成员作为成员,所以它被声明为类的朋友,并且在类中定义但不是类成员。这允许用户将两个 Operand 类实例或对象添加在一起,并将新计算的值作为 Operand 对象返回。我会将 cmets 添加到 snippet 部分,以了解正在使用哪些重载运算符。

sn-p

Operand A( 2.3f );
Operand B( 4.5f );
Operand C( 0 );
Operand D( 0 );

C = A + B;     // inline friend Operand Operand::operator+( const Operand& A, const Operand B );
D = C + 2.5f;  // Overloaded Operator Defined as Class Member
D = 3.4f + B;  // inline friend Operand Operand::operator+( const Value& value, const Operand A );

我已经使用 4 种常见的算术运算 +-*/ 完成了这项工作,其中一个运算符在类中定义为成员,并为 4 个运算中的每一个定义了 2 个友元运算符。这是类定义。

操作数.h

#ifndef OPERAND_H
#define OPERAND_H

class Operand {
public:
    static const float ZERO;

protected:
    float operand_;

public:
    explicit Operand( float a = float() ) : operand_( a ) {}

    inline float getOperand() const { 
        return operand_; 
    }


    inline Operand& operator+=( const float& value ) {
        operand_ += value;
        return *this;
    }

    inline Operand& operator-=( const float& value ) {
        operand_ -= value;
        return *this;
    }

    inline Operand& operator*=( const float& value ) {
        operand_ *= value;
        return *this;
    }

    inline Operand& operator/=( const float& value ) {
        if ( isZero( value ) ) {
            operand_ = 0;
        } else {
            operand_ /= value;
        }
    }

    inline Operand operator+() const { // Unary
        return *this; 
    }

    inline Operand operator+( const float& value ) const { 
        return Operand( operand_ + value ); 
    }

    inline Operand operator-() const { // Unary
        return Operand( -operand_ ); 
    }

    inline Operand operator-( const float& value ) const {
        return Operand( operand_ - value );
    }

    inline Operand operator*( const float& value ) const {
        return Operand( operand_ * value );
    }

    inline Operand operator/( const float& value ) const {
        if ( isZero( value ) ) {
            return Operand( 0 );
        } else {
            return Operand( operand_ / value );
        }
    }

    inline friend Operand Operand::operator+( const Operand& A, const Operand B ) {
        return Operand( A.getOperand() + B.getOperand() );
    }
    inline friend Operand Operand::operator+( const float& value, Operand A ) {
        return Operand( value + A.getOperand() );
    }

    inline friend Operand Operand::operator-( const Operand& A, const Operand B ) {
        return Operand( A.getOperand() - B.getOperand() );
    }
    inline friend Operand Operand::operator-( const float& value, Operand A ) {
        return Operand( value - A.getOperand() );
    }

    inline friend Operand Operand::operator*( const Operand& A, const Operand B ) {
        return Operand( A.getOperand() * B.getOperand() );
    }
    inline friend Operand Operand::operator*( const float& value, const Operand A ) {
        return Operand( value * A.getOperand() );
    }

    inline friend Operand Operand::operator/( const Operand& A, const Operand B ) {
        if ( isZero( B.getOperand() ) ) {
            return Operand( 0 ); 
        } else {
            return Operand( A.getOperand() / B.getOperand() );
        }
    }
    inline friend Operand Operand::operator/( const float& value, const Operand A ) {
        if ( isZero( A.getOperand() ) ) {
            return Operand( 0 );
        } else {
            return Operand( value / A.getOperand() );
        }
    }       

    inline static bool isZero( float value ) {
        if ( (value > -ZERO) && (value < ZERO) ) {
            return true;
        }
        return false;
    } // isZero

}; // Operand

// #include "Operand.inl"

#endif // OPERAND_H

操作数.cpp

#include "Operand.h"

const float Operand::ZERO = static_cast<float>(1e-7); 

我想要做的是模板这个类。

所以这里只是定义为类模板的同一个类:

OperandT.h

#ifndef OPERAND_T_H
#define OPERAND_T_H

template <typename T>
class OperandT {
public:
    static const T ZERO;

protected:
    T operand_;

public:

    explicit OperandT<T>( T a = T() ) : operand_( a ) {}

    inline T getOperand() const { 
        return operand_; 
    } // getOperand 

    inline OperandT<T>& operator+=( const T& value ) {
        operand_ += value;
        return *this;
    } // operator+=

    inline OperandT<T>& operator-=( const T& value ) {
        operand_ -= value;
        return *this;
    } // operator-=

    inline OperandT<T>& operator*=( const T& value ) {
        operand_ *= value;
        return *this;
    } // operator*=

    inline OperandT<T>& operator/=( const T& value ) {
        if ( isZero( value ) ) {
            operand_ = 0;
        } else {
            operand_ /= value;
        }
    } // operator/=

    inline OperandT<T> operator+() const { 
        return *this; 
    } // operator+ Unary

    inline OperandT<T> operator+( const T& value ) const { 
        return OperandT<T>( operand_ + value ); 
    } // operator+ Binary

    inline OperandT<T> operator-() const {
        return OperandT<T>( -operand_ ); 
    } // operator- Unary (Negate Value)

    inline OperandT<T> operator-( const T& value ) const {
        return OperandT<T>( operand_ - value );
    } // opeator- Binary (Subtraction)

    inline OperandT<T> operator*( const T& value ) const {
        return OperandT<T>( operand_ * value );
    } // operator* Post Multiply

    inline OperandT<T> operator/( const T& value ) const {
        if ( isZero( value ) ) {
            return OperandT<T>( 0 );
        } else {
            return OperandT<T>( operand_ / value );
        }
    } // operator/ Post Divide

    /*/ Having Trouble With Operators When Using Templates and Friends
    inline friend OperandT<T> OperandT<T>::operator+( const OperandT<T>& A, const OperandT<T> B ) {
        return OperandT<T>( A.getOperand() + B.getOperand() );
    }
    inline friend OperandT<T> OperandT<T>::operator+( const float& value, OperandT<T> A ) {
        return OperandT<T>( value + A.getOperand() );
    }

    inline friend OperandT<T> OperandT<T>::operator-( const OperandT<T>& A, const OperandT<T> B ) {
        return OperandT<T>( A.getOperand() - B.getOperand() );
    }
    inline friend OperandT<T> OperandT<T>::operator-( const float& value, OperandT<T> A ) {
        return OperandT<T>( value - A.getOperand() );
    }

    inline friend OperandT<T> OperandT<T>::operator*( const OperandT<T>& A, const OperandT<T> B ) {
        return OperandT<T>( A.getOperand() * B.getOperand() );
    }
    inline friend OperandT<T> OperandT<T>::operator*( const float& value, const OperandT<T> A ) {
        return OperandT<T>( value * A.getOperand() );
    }

    inline friend OperandT<T> OperandT<T>::operator/( const OperandT<T>& A, const OperandT<T> B ) {
        if ( isZero( B.getOperand() ) ) {
            return OperandT<T>( 0 ); 
        } else {
            return OperandT<T>( A.getOperand() / B.getOperand() );
        }
    }
    inline friend OperandT<T> OperandT<T>::operator/( const float& value, const OperandT<T> A ) {
        if ( isZero( A.getOperand() ) ) {
            return OperandT<T>( 0 );
        } else {
            return OperandT<T>( value / A.getOperand() );
        }
    } */

    inline static bool isZero( T value ) {
        if ( (value > -ZERO) && (value < ZERO) ) {
            return true;
        }
        return false;
    } // isZero

}; // OperandT

#include "OperandT.inl"

#endif // OPERAND_T_H

OperandT.cpp

#include "OperandT.h"

template <typename T>
const T OperandT<T>::ZERO  = static_cast<T>( static_cast<float>(1e-7) );

将友元运算符注释掉后,它可以编译,并且类中定义的运算符可以工作,但是当我取消注释类的下部时,我最终会遇到编译器错误。

我的几个问题是:

  • 是否有一种有效的方法来使用类模板定义友元运算符或函数?
  • 如果是这样,由于模板的陌生性,合适的语法是什么?
  • 如果不是,有哪些可能的替代方法来实现相同的功能以尽可能保持通用性?
  • 最后但并非最不重要的一点是,为什么朋友们在头等舱工作得很好,但是一旦添加了模板的概念,您最终会遇到火车事故?

【问题讨论】:

  • inline friend Operand Operand::operator+( const Operand&amp; A, const Operand B ) 是什么意思?
  • @Danh 添加到操作数对象一起查看顶部代码的 sn-p 部分。由于这是一个类对象,类定义运算符是类实例+值,其中两个朋友是值+类实例,而您要问的一个是类实例+另一个类实例。
  • 你测试了吗?我认为它不会起作用
  • 正确的方法是friend Operand operator+(Operand A, Operand B)friend Operand operator+(const Operand&amp; A, const Operand&amp; B),我要向MSFT 提交错误
  • 那就是编译器的bug

标签: c++ templates visual-studio-2015 operator-overloading friend


【解决方案1】:

在评论部分与Danh 进行了简短的交谈后,他让我注意到我能够在visual studio 2013 - 15 中实现overloaded friend operators 的方式应该被视为一个错误。是的,它将在 Visual Studio 以及 Visual Studio 编译器rextesters.com 的本网站上编译和运行而不会出错。他表示,实现重载友元运算符的正确方法如下:

正确的方法是friend Operand operator+(Operand A, Operand B)friend Operand operator+(const Operand&amp; A, const Operand&amp; B),我要向MSFT 提交错误- Danh

他还从这里向我展示了在 GCC 或 Clang 下编译失败的地方:http://melpon.org

我告诉他我会考虑到这一点,我做到了。所以我相应地更新了我的Operand 头文件,它可以正确编译、构建和运行。 然后我继续修复模板版本,它也可以正常工作。

这是更新的类头文件。

操作数.h

#ifndef OPERAND_H
#define OPERAND_H

class Operand {
public:
    static const float ZERO;

protected:
    float operand_;

public:
    explicit Operand( float a = float() ) : operand_( a ) {}

    inline float getOperand() const { 
        return operand_; 
    }


    inline Operand& operator+=( const float& value ) {
        operand_ += value;
        return *this;
    }

    inline Operand& operator-=( const float& value ) {
        operand_ -= value;
        return *this;
    }

    inline Operand& operator*=( const float& value ) {
        operand_ *= value;
        return *this;
    }

    inline Operand& operator/=( const float& value ) {
        if ( isZero( value ) ) {
            operand_ = 0;
        } else {
            operand_ /= value;
        }
    }

    inline Operand operator+() const { // Unary
        return *this; 
    }

    inline Operand operator+( const float& value ) const { 
        return Operand( operand_ + value ); 
    }

    inline Operand operator-() const { // Unary
        return Operand( -operand_ ); 
    }

    inline Operand operator-( const float& value ) const {
        return Operand( operand_ - value );
    }

    inline Operand operator*( const float& value ) const {
        return Operand( operand_ * value );
    }

    inline Operand operator/( const float& value ) const {
        if ( isZero( value ) ) {
            return Operand( 0 );
        } else {
            return Operand( operand_ / value );
        }
    }

    inline friend Operand operator+( const Operand& A, const Operand& B ) {
        return Operand( A.getOperand() + B.getOperand() );
    }
    inline friend Operand operator+( const float& value, const Operand& A ) {
        return Operand( value + A.getOperand() );
    }

    inline friend Operand operator-( const Operand& A, const Operand& B ) {
        return Operand( A.getOperand() - B.getOperand() );
    }
    inline friend Operand operator-( const float& value, const Operand& A ) {
        return Operand( value - A.getOperand() );
    }

    inline friend Operand operator*( const Operand& A, const Operand& B ) {
        return Operand( A.getOperand() * B.getOperand() );
    }
    inline friend Operand operator*( const float& value, const Operand& A ) {
        return Operand( value * A.getOperand() );
    }

    inline friend Operand operator/( const Operand& A, const Operand& B ) {
        if ( isZero( B.getOperand() ) ) {
            return Operand( 0 ); 
        } else {
            return Operand( A.getOperand() / B.getOperand() );
        }
    }
    inline friend Operand operator/( const float& value, const Operand& A ) {
        if ( isZero( A.getOperand() ) ) {
            return Operand( 0 );
        } else {
            return Operand( value / A.getOperand() );
        }
    }       

    inline static bool isZero( float value ) {
        if ( (value > -ZERO) && (value < ZERO) ) {
            return true;
        }
        return false;
    }    
}; // Operand

//#include "Operand.inl"

#endif // OPERAND_H

OperandT.h

#ifndef OPERAND_T_H
#define OPERAND_T_H

template <typename T>
class OperandT {
public:
    static const T ZERO;

protected:
    T operand_;

public:    
    explicit OperandT<T>( T a = T() ) : operand_( a ) {}

    inline T getOperand() const { 
        return operand_; 
    } 

    inline OperandT<T>& operator+=( const T& value ) {
        operand_ += value;
        return *this;
    } 

    inline OperandT<T>& operator-=( const T& value ) {
        operand_ -= value;
        return *this;
    } 

    inline OperandT<T>& operator*=( const T& value ) {
        operand_ *= value;
        return *this;
    } 

    inline OperandT<T>& operator/=( const T& value ) {
        if ( isZero( value ) ) {
            operand_ = 0;
        } else {
            operand_ /= value;
        }
    } 

    inline OperandT<T> operator+() const { 
        return *this; 
    } 

    inline OperandT<T> operator+( const T& value ) const { 
        return OperandT<T>( operand_ + value ); 
    } 

    inline OperandT<T> operator-() const {
        return OperandT<T>( -operand_ ); 
    } 

    inline OperandT<T> operator-( const T& value ) const {
        return OperandT<T>( operand_ - value );
    }

    inline OperandT<T> operator*( const T& value ) const {
        return OperandT<T>( operand_ * value );
    }

    inline OperandT<T> operator/( const T& value ) const {
        if ( isZero( value ) ) {
            return OperandT<T>( 0 );
        } else {
            return OperandT<T>( operand_ / value );
        }
    }

    inline friend OperandT<T> operator+( const OperandT<T>& A, const OperandT<T>& B ) {
        return OperandT<T>( A.getOperand() + B.getOperand() );
    }
    inline friend OperandT<T> operator+( const float& value, const OperandT<T>& A ) {
        return OperandT<T>( value + A.getOperand() );
    }

    inline friend OperandT<T> operator-( const OperandT<T>& A, const OperandT<T>& B ) {
        return OperandT<T>( A.getOperand() - B.getOperand() );
    }
    inline friend OperandT<T> operator-( const float& value, const OperandT<T>& A ) {
        return OperandT<T>( value - A.getOperand() );
    }

    inline friend OperandT<T> operator*( const OperandT<T>& A, const OperandT<T>& B ) {
        return OperandT<T>( A.getOperand() * B.getOperand() );
    }
    inline friend OperandT<T> operator*( const float& value, const OperandT<T>& A ) {
        return OperandT<T>( value * A.getOperand() );
    }

    inline friend OperandT<T> operator/( const OperandT<T>& A, const OperandT<T>& B ) {
        if ( isZero( B.getOperand() ) ) {
            return OperandT<T>( 0 ); 
        } else {
            return OperandT<T>( A.getOperand() / B.getOperand() );
        }
    }
    inline friend OperandT<T> operator/( const float& value, const OperandT<T>& A ) {
        if ( isZero( A.getOperand() ) ) {
            return OperandT<T>( 0 );
        } else {
            return OperandT<T>( value / A.getOperand() );
        }
    }

    inline static bool isZero( T value ) {
        if ( (value > -ZERO) && (value < ZERO) ) {
            return true;
        }
        return false;
    }
}; // OperandT

//#include "OperandT.inl"

#endif // OPERAND_T_H

感谢Danh

【讨论】:

    猜你喜欢
    • 2011-05-08
    • 2021-05-18
    • 2011-06-07
    • 2010-11-20
    • 2011-04-28
    • 1970-01-01
    相关资源
    最近更新 更多