我想在c ++中为我的video stabilization project创建一个完全自定义的流管道。
最终结果应类似于:
videofilelocation >> preprocessing() >> analyze() >> stabilize() >> video_out(outputfilename).flush();
因此,preprocessing
应该接受输入字符串并加载视频,提取帧等。之后,它应该返回自定义结构framevector
,该结构应传递给analyze
,依此类推。上。
不幸的是,关于如何实现完全自定义的流运算符,没有明确的教程/说明。 (仅用于std::ostream
等)
这怎么办?
答案 0 :(得分:1)
出于好奇,我将此视为难题,并得到了以下小例子:
#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)
基本原理受流运算符的启发:
operator>>
获得一个Object
引用,处理该对象(更改其状态)并返回该引用。这允许通过运算符链传递在表达式的最左参数中创建的对象。
要应用“类似操纵器的功能”,函子类与相应的operator>>
结合使用。
要提供无需()
就可以使用的“操纵器”,还需要一个全局实例。
答案 1 :(得分:1)
不幸的是,关于如何实现完全自定义的流运算符,没有明确的教程/说明。
好。这是一个简短的。
operator>>
是二进制运算符。为了使其具有灵活性,您需要将其编写为自由函数重载,这意味着您必须在每个步骤中自定义其含义。
为了获得上述语法,您正在寻找建立一个顶部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();
}
答案 2 :(得分:0)
此帮助吗?
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;