【发布时间】:2013-04-06 19:21:47
【问题描述】:
假设最初我使用 CRTP 进行了以下设计:
template<class Outputter> class Generator {
protected:
vector<int> v;
private:
void work(ostream& out) {
// perform first part of some complex operations on v
out << *static_cast<Outputter *>(this);
// perform second part of some complex operations on v
out << *static_cast<Outputter *>(this);
// many more ....
// perform some final actions
}
public:
Generator(unsigned length): v(length) {}
friend ostream& operator<<(ostream& out, Outputter&& generator) {
// perform some preparation work
work(out);
// perform some final actions
return out;
}
};
class SimpleDumpOutputter : public Generator<SimpleDumpOutputter> {
private:
unsigned count;
public:
SimpleDumpOutputter(unsigned length): Generator(length), count() {}
friend ostream& operator<<(ostream& out, SimpleDumpOutputter& outputter) {
out << "Step " << ++count << " of calculation: "
copy(outputter.v.begin(), outputter.v.end(), ostream_iterator<int>(out, " "));
out << endl;
return out;
}
};
class FancyOutputter : public Generator<FancyOutputter> { // create a graph using graphviz's dot language to visualise v
private:
// abbreviated
public:
FancyOutputter(unsigned length): Generator(length) {}
friend ostream& operator<<(ostream& out, FancyOutputter& outputter) {
// write statements to out
return out;
}
};
// some more different Outputters, for example an Outputter that creates a pretty LaTeX document
在这个设计中,有一个Generator CRTP 类模板,它对vector<int> v 执行复杂的计算,并使用其派生类的好友operator<< 在计算的每个步骤/部分打印结果。
我想实现一个有趣的概念:我希望在一次执行中以多种格式输出。具体来说,我认为我可以这样做:
template<class Outputters> class AggregateOutputter : public Generator<AggregateOutputter<Outputters...> > {
private:
static const unsigned outputter_count = sizeof...(Outputters);
typedef array<ostream *, outputter_count> DestArr;
DestArr destinations;
public:
AggregateOutputter(unsigned v_length, DestArr destinations): IsomerGenerator<AggregateOutputter<Outputters...> >(length), destinations(destinations) {}
friend ostream& operator<<(ostream&, AggregateOutputter& outputter); // first argument is dummy, because we would use the ostreams in destinations
}
这个想法是用户会使用,比如说,AggregateOutputter<SimpleDumpOutputter, FancyOutputter,并用两个ostreams 的array 来构造对象。每当Generator 在输出类上调用operator<< 时,AggregateOutputter 将遍历destinations 中的ostreams 和Outputters 中的类型,并调用类似于*dest_iter << *static_cast<Outputter_Iter>(this); 的内容。
我不确定这将如何工作。我不确定是否可以以这种方式使用多重继承,是否可以在array 和一组参数化类型之间“压缩”。有没有人了解这种情况?
【问题讨论】:
-
在您的原始版本中,您的
operator <<重载为friends,但使用的是this。这不会编译 -
@AndyProwl 我很抱歉。我试图简化生产代码但犯了一个错误。其实
operator<<调用私有成员函数work做实际工作。 -
你可以使用索引来压缩数组和类型列表。
-
@Pubby 那么你可以指定一个数字索引来访问类型包中的类型吗?我以前认为必须使用递归来“迭代”类型包。您是否建议类似于
tuple提供get<N>的方式? -
@kccqzy 它构造了一个 int 参数包,您可以使用
...对其进行扩展,请参见:loungecpp.wikidot.com/tips-and-tricks:indices
标签: c++ templates c++11 variadic-templates crtp