开发者

need some kind of operator.. c++

I want to store a sequence of string in a queue. This seems pretty simple if i use the member function push()

queue test;
string s0("s0"), s1("s1");

test.push(s0);
test.push(s1);

I am thinking about adding the strings in the queue 开发者_如何学Goin implicitly way. That mean, if I type the following sequence of string the e.g. operator >> should push the string value in the queue.

queue test;
string s0("s0"), s1("s1");

s0 >> s1 >> s2 >> s3 ;

is there any way to do that?


While C++ doesn't allow you this, it allows you to do something very similar: test << s0 << s1; However, don't do this!

If I see test.push(s0), I know exactly what it does, without even looking at the type of test. If I see test << s0 << s1;, I'd think test is a stream that's written to.


Here's my three basic rules you should stick to when overloading operators:

  1. Despite seemingly obvious contrary evidence, there only are surprisingly few cases where operator overloading is appropriate. Consequentially, the first and foremost rule for overloading operators, at its very heart, says: Don’t do it. That might seem strange, but the reason is that actually it is hard to understand the semantics behind the application of an operator unless the use of the operator in the application domain is well known and undisputed. Contrary to popular believe, this is hardly ever the case. Whenever the meaning of an operator is not obviously clear and undisputed, it should not be overloaded. Instead, provide a function with a well-chosen name.
  2. C++ poses few limitations on the semantics of overloaded operators. Your compiler will happily accept code that implements the binary + operator to change its right operand. However, the users of such an operator would never suspect the expression a + b to change the value of b. This is why the second rule of operator overloading says: Always stick to the operator’s well-known semantics. (This, in turn, presumes that the semantics are undisputed; see the previous rule.)
  3. Finally, always remember that operators are related to each other and to other operations. If your type supports a + b, users will expect to be able to call a += b, too. If it supports prefix increment ++a, they will expect a++ to work, too. If they can check whether a < b, they will most certainly expect to also to be able to check whether a > b. If they can copy-construct your type, they expect assignment to work as well. So the third rule of operator overloading reminds you: Always provide all out of a set of related operations.

As with all such rules, there are indeed exceptions. Sometimes people have deviated from them and the outcome was not bad code, but such deviations are few and far between. At the very least, 99 out of 100 such deviations I have seen were unjustified. However, it might just as well have been 999 out of 1000. So you’d better stick to these rules.

So just in case I hadn't been clear enough: For the code from your question, a deviation from these rules is very bad.


First off, your example of 'implicitly' enqueueing items has no mention of the queue - do you mean something like:

test << s0 << s1 << s2 << s3;

If so, it's possible, but I wouldn't recommend it. It really doesn't help readability that much. If you really do want it, though, put this in a header somewhere and include it wherever you want this behavior:

template<typename T>
std::queue<T> &operator<<(std::queue<T> &q, const T &v)
{
    q.push(v);
    return q;
}

Note that the opposite order - s0 >> s1 >> s2 >> test - is not possible, due to C++ precedence rules.


I would not really do it, but if you really feel that you need to provide that syntax, you can write an inserter adapter...

template <typename C>
class inserter_type {
public:
   typedef C container_type;
   typedef typename container_type::value_type value_type;

   explicit inserter_type( container_type & container ) : container(container) {}
   inserter_type& operator<<( value_type const & value ) {
      container.push( value );
      return *this;
   }
private:
   container_type & container;
};
template <typename C>
inserter_type<C> inserter( C & container ) {
   return inserter_type<C>(container);
}
int main() {
   std::queue<std::string> q;
   inserter(q) << "Hi" << "there";
}


Qt containers work exactly like this:

QStringList list;
list << "Sven" << "Kim" << "Ola";

QVector<QString> vect = list.toVector();
// vect: ["Sven", "Kim", "Ola"]

If you want the same to work with STL containers, you would need to write the operator overloading yourself but obviously you can't add operations to std namespace.


If you wanted to do this it would typically be expressed as

test << s0 << s1 << s2 << s3;

by suitable definition of overloaded operator<< on the queue class. I don't know why this would be better than a simple series of test.push() calls though.


I agreed with most answers, which told you that you could do it, as long as you included the queue object, and I also agree that readability is compromised since it's a very non-standard behavior.

Still, I was wondering. What if you try something like:

queue test;
string s0("s0"), s1("s1");

test.push(s0).push(s1);

That could be implemented very simply, would still give you the correct readability (since the meaning of push is well understood), and keep your code concise (which seems to be your main objective).

To implement it, all you'd have to do is extend the Queue class (or write your own queue class which would, in turn, wrap around an STL Queue object).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜