How to know the number of chain custom-defined operator << calls?

  • A+
Category:Languages

I have my own class where I define and use << operator like so:

vw& vw::operator<<(const int &a) {      // add a to an internal buffer     // do some work when it's the last number      return *this; }  ...  vw inst;  inst << a << b << c << d;  ...  inst << a << b;  ... 

The number of chain << calls is different every time. These numbers together represent a code and I need to do something when the code is complete.

Do I have any other options to know when it's complete rather than adding a special terminating value to each chain, like below?

inst << a << b << c << d << term;  ...  inst << a << b << term; 

EDIT : I'm trying to implement LogicStuff solution, here is the full code I got so far:

--- chain.h --- #pragma once #include <iostream> class chain { public:     chain();     ~chain(); }; --- chain_cutter.h --- #pragma once #include "chain.h" class chain_cutter {     chain &inst; public:     explicit chain_cutter(chain &inst) : inst(inst) {         std::cout << "cutter_constructor" << std::endl;     }     ~chain_cutter(); }; --- chain_cutter.cpp --- #include "stdafx.h" #include "chain_cutter.h" chain_cutter::~chain_cutter() {     std::cout << "cutter_destructor" << std::endl; } --- chain.cpp --- #include "stdafx.h" #include "chain.h" chain::chain() {     std::cout << std::endl << "chain_constructor" << std::endl; } chain::~chain() {     std::cout << std::endl << "chain_destructor" << std::endl; } --- flowchart.cpp ---  #include "stdafx.h"  #include <iostream>  #include "chain.h" #include "chain_cutter.h"  chain_cutter operator<<(chain &inst, const int &a) {     chain_cutter cutter(inst);     std::cout << a << std::endl;     return cutter; }  chain_cutter operator<<(chain_cutter cutter, const int &a) {     std::cout << a << std::endl;     return cutter; }  int main() {      std::cout << "main start" << std::endl;      chain ch;      ch << 1 << 2 << 3;      std::cout << std::endl << "-----" << std::endl;      ch << 4 << 5;      return 0; } 

This is the output:

main start  chain_constructor cutter_constructor 1 2 cutter_destructor 3 cutter_destructor cutter_destructor cutter_destructor cutter_destructor  ----- cutter_constructor 4 5 cutter_destructor cutter_destructor cutter_destructor  chain_destructor 

Q. Am I doing something wrong - I see a lot of destructors, not one per chain?

 


It is possible without changing the current syntax.

You will have to make inst << a (i.e. the current operator<<) return a temporary instance of a "special" class, holding a reference to inst, implementing operator<< by calling inst.operator<<, returning reference to *this, and then doing the extra work in its destructor, which will be called at the end of the statement.

And yes, you can keep track of the call count with it.


I propose these nonmember operator<< overloads (vw_chain is the new proxy class):

// Left-most operator<< call matches this vw_chain operator<<(vw &inst, const int &a) {     return vw_chain(inst, a); }  // All subsequent calls within the << chain match this vw_chain &&operator<<(vw_chain &&chain, const int &a) {     chain.insert(a);     return std::move(chain); } 

The class itself:

struct vw_chain {     explicit vw_chain(vw &inst, const int &a) :         inst(inst)     {         insert(a);     }      ~wv_chain() {         // do something     }      void insert(const int &a) {         // This, the original operator<<, should be made accessible only to this         // function (private, friend class declaration?), not to cause ambiguity.         // Or, perhaps, put the implementation of the original operator<< here         // and remove it altogether.         inst << a;         ++insertion_count;     }      vw &inst;     size_t insertion_count = 0; }; 

We have to pass the instance around by rvalue reference. We do the first insertion inside the vw_chain's constructor, in order to get the mandatory copy elision (C++17), which works only with prvalues. Whether there will be a copy done at the return statement, is unspecified with NRVO and older standards. We should not rely on that.

Pre-C++17 solution:

struct vw_chain {     // We keep the constructor simpler     vw_chain(vw &inst) : inst(inst) {}      // Moved-from chains are disabled     vw_chain(vw_chain &&other) :         inst(other.inst),         insertion_count(other.insertion_count) {         other.is_enabled = false;     }      // And will not call the termination logic     ~vw_chain() {         if(is_enabled) {             // do something         }     }      void insert(const int &a) {         inst << a;         ++insertion_count;     }      vw &inst;     size_t insertion_count = 0;     bool is_enabled = true; };  // The first overload changes to this vw_chain operator<<(vw &inst, const int &a) {     vw_chain chain(inst);     chain.insert(a);     return chain; } 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: