Из любопытства я взял это как загадку и получил следующий небольшой пример:
#include <iostream>
#include <string>
// a sample object which is subject of object stream
struct Object {
// contents
std::string name;
int a, b;
// constructors.
Object(int a, int b): a(a), b(b) { }
Object(const std::string &name, int a, int b):
name(name), a(a), b(b)
{ }
};
// a functor to initialize an object (alternatively)
struct source {
Object &obj;
source(Object &obj, int a, int b): obj(obj)
{
this->obj.a = a; this->obj.b = b;
}
operator Object& () { return obj; }
};
// a clear functor
struct clear {
clear() = default;
Object& operator()(Object &in) const
{
in.a = in.b = 0;
return in;
}
};
// make clear functor applicable to object "stream"
Object& operator>>(Object &in, const clear &opClear)
{
return opClear(in);
}
// a global instance
static clear reset;
// an add functor
struct add {
const int da, db;
add(int da, int db): da(da), db(db) { }
Object& operator()(Object &in) const
{
in.a += da; in.b += db;
return in;
}
};
// make add functor applicable to object "stream"
Object& operator>>(Object &in, const add &opAdd)
{
return opAdd(in);
}
// a display functor
struct echo {
const std::string label;
explicit echo(const std::string &label = std::string()):
label(label)
{ }
Object& operator()(Object &in) const
{
std::cout << label
<< "Object '" << in.name << "' (" << in.a << ", " << in.b << ")\n";
return in;
}
};
// make display functor applicable to object "stream"
Object& operator>>(Object &in, const echo &opEcho)
{
return opEcho(in);
}
// a sink functor (actually not needed)
struct null {
null() = default;
void operator()(Object&) const { }
};
// make echo functor applicable to object "stream"
void operator>>(Object &in, const null &opNull) { opNull(in); }
// check it out:
int main()
{
Object obj("obj1", 12, 34);
// either use obj as source
obj
>> echo("before add(-2, -4): ")
>> add(-2, -4)
>> echo("after add(-2, -4): ")
>> reset
>> echo("after reset: ")
>> null();
// or a source operator
source(obj, 11, 22)
>> echo("before add(11, -11): ")
>> add(11, -11)
>> echo("after add(11, -11): ");
return 0;
}
Вывод:
before add(-2, -4): Object 'obj1' (12, 34)
after add(-2, -4): Object 'obj1' (10, 30)
after reset: Object 'obj1' (0, 0)
before add(11, -11): Object 'obj1' (11, 22)
after add(11, -11): Object 'obj1' (22, 11)
Live Demoon coliru
Основной принцип основан на операторах потока:
operator>>
s получает ссылку Object
, обрабатывает объект (изменяя егосостояние) и вернуть ссылку.Это позволяет передавать объект, созданный в самом левом аргументе выражения, через цепочку операторов.
Чтобы применить «функцию как манипуляторы», классы функторов используются в сочетании с соответствующими operator>>
.
Для предоставления «манипуляторов», которые могут использоваться без ()
, глобального экземпляратребуется дополнительно.