Как узнать количество цепочек пользовательских операторов << звонков? - PullRequest
0 голосов
/ 08 октября 2018

У меня есть свой собственный класс, в котором я определяю и использую оператор << следующим образом: </p>

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;

...

Количество вызовов цепочки << каждый раз разное.Эти числа вместе представляют код, и мне нужно что-то сделать, когда код будет завершен. </p>

Есть ли у меня какие-либо другие варианты, чтобы знать, когда он завершится, вместо добавления специального завершающего значения в каждую цепочку, как показано ниже?

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

...

inst << a << b << term;

EDIT2 : текущее решение, следующее за LogicStuff ответы:

--- 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 std::move(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;
}

Это вывод:

main start

chain_constructor
cutter_constructor
1
2
3
cutter_destructor

-----
cutter_constructor
4
5
cutter_destructor

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

Это возможно без изменения текущего синтаксиса.

Вам придется заставить inst << a (то есть текущий operator<<) возвращать временный экземпляр "специального" класса, содержащего ссылку на inst, реализуя operator<<, вызывая inst.operator<<, возвращая ссылку на *this, а затем выполняя дополнительную работу в своем деструкторе, который будет вызываться в конце оператора.

И да,Вы можете отслеживать количество вызовов с ним.


Я предлагаю следующие не члены operator<< перегрузки (vw_chain - новый прокси-класс):

// 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);
}

Сам класс:

struct vw_chain
{
    explicit vw_chain(vw &inst, const int &a) :
        inst(inst)
    {
        insert(a);
    }

    ~vw_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;
};

Мы должны передать экземпляр по ссылке rvalue.Мы делаем первую вставку внутри конструктора vw_chain, чтобы получить обязательную копию elision (C ++ 17), которая работает только с prvalues.Будет ли копия сделана в операторе return, не определено в NRVO и более старых стандартах.Мы не должны полагаться на это.

Решение до C ++ 17:

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;
}
0 голосов
/ 08 октября 2018

Вы можете:

  • Использовать специальный конечный тип для сигнализации окончания (а-ля std::endl).

  • Избегать использования operator<< и вместо этого определяем шаблонную функцию.Функция шаблона variadic поддерживает любое количество произвольных аргументов и знает это число во время компиляции.

  • Поместите логику в деструктор vw и разрешите operator<< только вrvalues.Например,

    vw{} << a << b << c;
    // `vw::~vw()` contains termination logic
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...