C++ 如何将CRTP与可变模板一起使用?
假设我最初使用CRTP进行了以下设计:C++ 如何将CRTP与可变模板一起使用?,c++,templates,c++11,variadic-templates,crtp,C++,Templates,C++11,Variadic Templates,Crtp,假设我最初使用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<Ou
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
这个想法是,用户可以使用,比如,
aggregateOutput我修改了您的原始设计。我认为生成器在调用输出操作符时进行一系列计算至少可以说是令人惊讶的。另外,为了让AggregateOutputter输出忽略的ostream参数,好的,在受到John Bandela解决方案的启发后,我提出了一个解决方案。(关于为什么我认为他的方法不适合我的需要,请参见我对答案的评论)
模板类聚合输出:公共生成器{
私人:
typedef数组DestArr;
去目的地;
typedef typename DestArr::迭代器destarter;
结构输出器持有者:公共输出器{
输出器保持器(向量和向量):输出器(向量)…{}
}输出端固定器;
模板结构OutputHelper{
静态无效do_输出(OutputterHolder*pthis,DestCarrieter dest){
**dest在您的原始版本中,您的运算符@AndyProwl对此我很抱歉。我试图简化生产代码,但犯了一个错误。实际上运算符您可以使用称为索引的东西压缩数组和类型列表。@Pubby,以便您可以指定数字索引来访问类型包中的类型?我以前认为ecursion必须用于“迭代”类型包。您是否建议类似于tuple
提供的get
?@kccqzy它构造了一个int参数包,您可以使用进行扩展…
查看此内容:非常感谢您的回答。我确实认为我的设计看起来有点奇怪,下面是我的基本原理:调用时进行大量计算运算符之所以使用CRTP而不是将输出传递给生成器,是因为输出非常复杂,需要调用生成器的受保护的
成员函数来完成部分工作。
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
}
#include <vector>
#include <iostream>
#include <iterator>
#include <array>
using namespace std;
class Generator {
protected:
vector<int> v;
public:
Generator(unsigned length): v(length) {}
template<class Outputter>
void do_calculations_with_output(Outputter& out){
// perform first part of some complex operations on v
out.output(v);
// perform second part of some complex operations on v
out.output(v);
// perform some final actions
}
};
class SimpleDumpOutputter {
private:
ostream* out;
unsigned count;
public:
SimpleDumpOutputter(ostream& os): out(&os), count() {}
template<class C>
void output(const C& c) {
*out << "Step " << ++count << " of calculation: ";
copy(c.begin(),c.end(), ostream_iterator<int>(*out, " "));
*out << endl;
}
};
class FancyOutputter {
ostream* out;
int count;
public:
FancyOutputter(ostream& os): out(&os),count() {}
template<class C>
void output(const C& c) {
// create a graph using graphviz's dot language to ease visualisation of v
*out << "Step " << ++count << " of calculation: ";
*out << "Graphviz output\n";
}
};
template<class... Outputters> class AggregateOutputter : private Outputters... {
private:
template<class First, class... Rest>
struct output_helper{
template<class C>
static void do_output(AggregateOutputter* pthis,const C& c){
static_cast<First*>(pthis)->output(c);
output_helper<Rest...>::do_output(pthis,c);
}
};
template<class First>
struct output_helper<First>{
template<class C>
static void do_output(AggregateOutputter* pthis,const C& c){
static_cast<First*>(pthis)->output(c);
}
};
public:
template<class... Out>
AggregateOutputter( Out&... out): Outputters(out)...{}
template<class C>
void output(const C& c) {
output_helper<Outputters...>::do_output(this,c);
}
};
int main(){
AggregateOutputter<FancyOutputter,SimpleDumpOutputter> out(cout,cout);
Generator g(10);
g.do_calculations_with_output(out);
}
template<class... Outputters> class AggregateOutputter : public Generator<AggregateOutputter<Outputters...> > {
private:
typedef array<ostream *, sizeof...(Outputters)> DestArr;
DestArr destinations;
typedef typename DestArr::iterator DestArrIter;
struct OutputterHolder : public Outputters... {
OutputterHolder(vector<int>& v): Outputters(v)... {}
} outputter_holder;
template<class First, class... Rest> struct OutputHelper {
static void do_output(OutputterHolder *pthis, DestArrIter dest) {
**dest << *static_cast<First *>(pthis);
OutputHelper<Rest...>::do_output(pthis, ++dest);
}
};
template<class First> struct OutputHelper<First> {
static void do_output(OutputterHolder *pthis, DestArrIter dest) {
**dest << *static_cast<First *>(pthis);
}
};
public:
template<typename... OstreamStar> AggregateOutputter(unsigned length, OstreamStar... ostreams): Generator<AggregateOutputter<Outputters...> >(length), destinations{{ostreams...}}, outputter_holder(this->v) {
static_assert(sizeof...(OstreamStar) == sizeof...(Outputters), "number of outputters and destinations do not match");
}
friend ostream& operator<<(ostream& dummy_out, AggregateOutputter& outputter) {
OutputHelper<Outputters...>::do_output(&outputter.outputter_holder, outputter.destinations.begin());
// possibly write some logging info to dummy_out
return dummy_out;
}
};
// to use this:
ofstream fout("gv.gv");
cout << AggregateOutputter<FancyOutputter, SimpleDumpOutputter>(length, &fout, &cout);