overloading operator<< to change member vari

2019-09-05 07:08发布

I have a class that looks something like this:

class A {
  public:
    A() {};
    A& operator<< (A& a, unsigned int i);

  private:
    vector<int> abc;
}

I want to offer the ability to add objects to abc using an operator:

A a();
a << 3,4,5; // should do the same as several calls of abc.push_back(i)

I know that I have to overload the << operator, do I also have to overload the , operator?

How would the actual method look like?

3条回答
Rolldiameter
2楼-- · 2019-09-05 07:38

The Eigen library implements this syntax. Not sure if that's where you're coming from.

Eigen is an expression template library. It defines operators and functions which appear to do things, but are just factories for proxy objects. The proxies form compile-time, and sometimes runtime data structures which decide when and how a computation should be done.

To realize this syntax, you'll need proxy objects. Think of it analogously to std::ostream. a << 3 returns a proxy "stream" object, which then overloads operator , to enable the , 4, 5 part. The proxy could just as well overload operator<<, in which case the syntax would be a << 3 << 4 << 5. This is arguably cleaner, but Eigen is a math- and operator-overloading-intensive library, and , has a special position as the lowest-precedence operator, which reduces the possibility of precedence mistakes in such an initialization as a << 3, true? 4 : 42, 5.

Long story short, you should probably stick to just operator<< even if you do it this way.

class A {
  public:
    A() {};

    inserter operator << (A& a, unsigned int i) {
      inserter ret( * this );
      ret , i;
      return ret;
    }

  private:
    vector<int> abc;

    struct inserter {
      A &client;

      inserter( A &in_client ) : client( in_client ) {}

      inserter &operator , ( int x ) {
        client.abc.push_back( x );
        return this;
      }
    };
    friend struct inserter;
};
查看更多
时光不老,我们不散
3楼-- · 2019-09-05 07:42

If you want to keep the aspect of a << 1, 2, 3 you could change your overloading of operator<< to accept an initializer_list of int, instead of a single int.

#include <initializer_list>

class A {
    public:
    A() {};
    A& operator<< (std::initializer_list<int> values);

    private:
    vector<int> abc;
}

Then implement it like:

A& A::operator<< (std::initializer_list<int> values)
{
    for(const auto& value : values)
        abc.push_back(value);
    return *this;
}

And simply use it as follows :

A a;
a << {1, 2, 3, 4};

The only thing you need to make sure is you have a C++11 compliant compiler that provides these features.

查看更多
冷血范
4楼-- · 2019-09-05 07:54

Never, ever, ever overload the , operator in C++. The language allows for it, but you can't do it and preserve the expected behavior of the operator. (In particular, the comma operator is a sequence point in C++: the compiler guarantees that the left-hand expression will be evaluated before the right-hand expression. If you overload it, there are no longer any guarantees about which expression will be evaluated first.)

You want to use multiple invocations of your stream insertion operator to insert multiple objects.

(For completeness: th eother C++ operators you should never overload are && and ||. Again, it's impossible to provide the behavior that client code will expect (short circuiting, in this case)).

查看更多
登录 后发表回答