How to overload operators with a built-in return type?

后端 未结 4 822
时光说笑
时光说笑 2021-01-23 06:56

Say I have a class, that wraps some mathematic operation. Lets use a toy example

class Test
{
public:
   Test( float f ) : mFloat( f ), mIsInt( false ) {}

   fl         


        
相关标签:
4条回答
  • 2021-01-23 07:27

    You can't "overload/add" operators for basic types, but you can for your type Type. But this shall not be operator = but operator >> - like in istreams.

    class Test
    {
    public:
       float mFloat;
       int   mInt;
       bool  mIsFloat;
       Test& operator >> (float& v) { if (mIsFloat) v = mFloat; return *this; }
       Test& operator >> (int& v) { if (!mIsFloat) v = mInt; return *this; }
    };
    

    Then you can:

    int main() {
      float v = 2;
      Test t = { 1.0, 2, false };
      t >> v; // no effect
      t.mIsFloat = true;
      t >> v; // now v is changed
    }   
    

    Update

    I want to do something like:

    updateTime = config["system.updateTime"];
    

    Then with my proposal, you cam:

    config["system.updateTime"] >> updateTime;
    
    0 讨论(0)
  • 2021-01-23 07:35

    You already have one implicit conversion from float to Test, in the form of the convert constructor

    class Test
    {
    public:
     /* ... */
    Test( float f ) : mFloat( f ) /*...*/ {}       
    
    };
    

    Which will support conversions such as:

    Test t(0.5f);
    

    You will likely also want a copy-assignement operator in order to make further implicit conversions from float to Test possible:

    class Test
    {
    public:
    
        Test& operator=(float f) { mFloat = f; return *this; }  
    };
    
    t = 0.75; // This is possible now
    

    In order to support implicit conversion from Test to float you don't use operator=, but a custom cast operator, declared & implemented thusly:

    class Test
    {
    public:
      /* ... */
      operator float () const { return mFloat; }
    };
    

    This makes implicit conversions posslible, such as:

    float f = t;
    

    As an aside, you have another implicit conversion happening here you may not even be aware of. In this code:

    Test t( 0.5 );
    

    The literal value 0.5 isn't a float, but a double. In order to call the convert constructor this value must be converted to float, which may result in loss of precision. In order to specify a float literal, use the f suffix:

    Test t( 0.5f );
    
    0 讨论(0)
  • 2021-01-23 07:35

    Using template specialization:

    class Config {
        template<typename T>
        void setValue(const std::string& index, T& value); //sets the value if available
    };
    
    template<float>
    void Config::setValue(const std::string& index, float& value){...} //only sets float values
    
    template<int>
    void Config::setValue(const std::string& index, int& value){...} //only sets int values;
    
    0 讨论(0)
  • 2021-01-23 07:37

    Based on your example, what you really want is an implicit conversion operator:

    class Test
    {
        // ...
    public:
        operator float() const;
    };
    
    inline Test::operator float() const
    {
        return mIsFloat ? mFloat : mInt;
    }
    

    If you want to conditionally do the assignment, then you need to take another approach. A named method would probably be the best option, all things considered... something like this:

    class Test
    {
    public:
        bool try_assign(float & f) const;
    };
    
    inline bool Test::try_assign(float & f) const
    {
        if (mIsFloat) {
            f = mFloat;
        }
    
        return mIsFloat;
    }
    

    Whatever you do, be careful that the syntactic sugar you introduce doesn't result in unreadable code.

    0 讨论(0)
提交回复
热议问题