Полностью настраиваемый оператор потока в C ++ - PullRequest
0 голосов
/ 10 октября 2018

Я хочу создать полностью настраиваемый конвейер потока для моего проекта стабилизации видео в c ++.

Конечный результат должен выглядеть следующим образом:

videofilelocation >> preprocessing() >> analyze() >> stabilize() >> video_out(outputfilename).flush();

Следовательно, preprocessing должен принять входную строку и загрузить видео, извлечь кадры и т. Д. После этого он должен возвратить пользовательскую структуру framevector, которая должна быть передана в analyze и т. Д.

К сожалению, естьнет четкого руководства / объяснения о том, как реализовать полностью настраиваемые потоковые операторы.(Только для std::ostream и т. Д.)

Как это можно сделать?

Ответы [ 3 ]

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

Из любопытства я взял это как загадку и получил следующий небольшой пример:

#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>>.

Для предоставления «манипуляторов», которые могут использоваться без (), глобального экземпляратребуется дополнительно.

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

К сожалению, нет четкого руководства / объяснения о том, как реализовать полностью настраиваемые потоковые операторы.

ОК.Вот короткий.

operator>> - бинарный оператор.Чтобы сделать его более гибким, вам нужно написать его как свободную функцию перегрузки , что означает, что вы можете настраивать его значение на каждом шаге.

Для того, чтобы получить синтаксис вышевы хотите построить цепочку вызовов top operator>> таким образом, чтобы вывод одного из них был первым аргументом следующего.

, поэтому a >> b >> c действительно означает: operator>>(operator>>(a, b), c) обратите внимание, что выводa >> b - это первый вход (a >> b) >> c.

Вот очень упрощенная цепочка, которая компилируется.Вы заметите, что я использовал семантику значений везде.Если ваши объекты шага обработки являются объектами строгой функции, вы можете передать их на const&.Если они переносят состояние из предыдущих применений, вам понадобятся перегрузки для && ссылок на r-значения.

#include<fstream>
#include<string>

// a representation of video data
// note-a value type so it will want to own its actual data through a 
// unique_ptr or similar.
struct video_data
{
};

struct preprocessing
{
    void process(video_data&);
};

struct analyze
{
    void process(video_data&);
};

struct stabilize
{
    void process(video_data&);
};

struct video_out
{
    video_out(std::string const& where);
    void process(video_data&);
};

struct flush
{
    void process(video_out&);
};

// now define the interactions
auto operator>>(std::string const& path, preprocessing proc) -> video_data
{
    video_data dat;
    proc.process(dat);
    return dat;
}

auto operator>>(video_data dat, analyze proc) -> video_data
{
    proc.process(dat);
    return dat;
}

auto operator>>(video_data dat, stabilize proc) -> video_data
{
    proc.process(dat);
    return dat;
}

auto operator>>(video_data dat, video_out proc) -> video_out
{
    proc.process(dat);
    return std::move(proc);
}

auto operator>>(video_out dat, flush proc) -> video_out
{
    proc.process(dat);
    return std::move(dat);
}

// now build a chain
int test(std::string const& videofilelocation, std::string const& outputfilename)
{
    videofilelocation >> preprocessing() >> analyze() >> stabilize() >> video_out(outputfilename) >> flush();
} 
0 голосов
/ 10 октября 2018

Помогает ли это:

class FileLocation        {};
class PreProcessedData    {};

class PreProcessingAction {
    public:
        PreProcessedData doStuff(FileLocation const& file) const
        {
            return PreProcessedData{};
        }
};

PreProcessingAction preprocessing() {
    return PreProcessingAction{};
}

PreProcessedData operator>>(FileLocation const& file, PreProcessingAction const& action)
{
    return action.doStuff(file);
}

int main()
{
    FileLocation   location;

    location >> preprocessing();
}

Если честно, кажется, что это усложняет код, а не помогает.

Не будет ли проще сделать что-то вроде этого:

Data     file            = readData("InputName");
Data     preProcData     = preprocessing(file);
Data     analysedData    = analyze(preProcData);
Data     stabalizedData  = stabilize(analysedData);

Output   output("OutputName");    
output << stabalizedData;
...