如何将CRTP与可变参数模板一起使用? [英] How to use CRTP with variadic templates?

查看:88
本文介绍了如何将CRTP与可变参数模板一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们最初使用CRTP进行以下设计:

Let's suppose originally I have the following design using 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<< 来打印计算的每个步骤/部分的结果。

In this design, there is a Generator CRTP class template that performs complex calculations on the vector<int> v and prints the result at each step/part of calculation using its derived classes's befriended operator<<.

这是我要实现的一个有趣的概念:我希望在一次执行中以多种格式输出。具体来说,我想我可以做到:

Here's an interesting concept that I want to implement: I would want outputs in multiple formats in a single execution. Specifically, I thought I could do:

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 并使用 array 构造两个对象 ostream s。每当 Generator 在输出程序类上调用 operator <<<时, AggregateOutputter 将迭代目的地中的 ostream s和 Outputters code>并沿 * dest_iter<< * static_cast< Outputter_Iter>(this);

The idea is that the user would use, say, AggregateOutputter<SimpleDumpOutputter, FancyOutputter and construct the object with an array of two ostreams. Whenever Generator calls operator<< on the outputter class, the AggregateOutputter will iterate through the ostreams in destinations and the types in Outputters and invoke something along the lines of *dest_iter << *static_cast<Outputter_Iter>(this);.

我不确定这如何工作。我不确定是否可以通过这种方式使用多重继承,也不确定是否可以在数组和一堆参数化类型之间压缩。

I'm not sure how this would work though. I'm not sure whether multiple inheritance can be used this way, whether it is possible to "zip" between an array and a pack of parameterised types. Is anyone knowledgable in this situation?

推荐答案

我修改了您的原始设计。我认为,至少可以说,在调用输出运算符时Generator进行了大量的计算。还要让您的AggregateOutputter输出以忽略<<的ostream参数。也令人惊讶。另外,Outputter与Generator不存在is-a关系。

I modified your original design. I thought Generator doing a bunch of calculations when the output operator is called is surprising to say the least. Also for your AggregateOutputter to output to ignore the ostream parameter of << is also surprising. Also, Outputter does not have an is-a relationship with Generator.

我试图找出问题所在,最终没有使用CRTP而是使用可变参数模板,但是我认为它可以满足您的要求。

I tried to separate out the concerns, and ended up not using CRTP but using variadic templates, but I think it does what you want.

http://ideone.com / xQrnW4

#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);

}

这篇关于如何将CRTP与可变参数模板一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆