C++ C++;11可变模板&x2B;遗产

C++ C++;11可变模板&x2B;遗产,c++,templates,c++11,inheritance,variadic-templates,C++,Templates,C++11,Inheritance,Variadic Templates,我想用可变模板写一个线性叠加的抽象。为此,我想定义一个基类型,它展示了某种形式的运算符(),如下所示 模板 类可叠加{ 公众: 类型定义结果\u t; void运算符()(结果和结果,常量参数和…)常量=0; }; 然后针对当前问题继承它,例如 class MyField : public Superposable<double, double, double> { public: void operator()(double& result, const do

我想用可变模板写一个线性叠加的抽象。为此,我想定义一个基类型,它展示了某种形式的运算符(),如下所示

模板
类可叠加{
公众:
类型定义结果\u t;
void运算符()(结果和结果,常量参数和…)常量=0;
};
然后针对当前问题继承它,例如

class MyField : public Superposable<double, double, double> {
  public:
    void operator()(double& result, const double& p1, const double& p2) const {
      result = p1 + p2;
    }
};
class MyField:公共可叠加{
公众:
void运算符()(双精度和结果、常数双精度和p1、常数双精度和p2)常数{
结果=p1+p2;
}
};
然后我想写一个抽象基类,它可以形成线性叠加,并得到可叠加的派生类作为模板参数,以确定operator()的调用签名。我想要点像这样的

template<typename S> // where S must be inherited from Superposable
class Superposition {
  private:
    std::vector< std::shared_ptr<S> > elements;
  public:

     // This is the problem. How do I do this?
    void operator()(S::result_t& result, const S::Parameters&... parameters) const {
       for(auto p : elements){
          S::result_t r;
          p->operator()(r, parameters);
          result += r;
       }
    }
};
template//其中S必须从supplicatable继承
类叠加{
私人:
std::vector元素;
公众:
//这就是问题所在。我该怎么做?
void操作符(){
用于(自动p:元素){
S::结果r;
p->operator()(r,参数);
结果+=r;
}
}
};
以下是我的问题:

  • 如何从可叠加的派生类中读取类型信息以在叠加中定义运算符()
  • 另外,是否有一种建议的方法来强制执行叠加只能用一个可叠加的派生类作为参数来调用
  • 一个更好的解决方案当然是编写一个叠加类,它不需要从基类派生MyField,而是直接解析MyField的运算符()。我可以这样做吗

  • 谢谢你的帮助

    首先,直接解决您的问题

    一些元编程样板:

    template<class...>struct types{using type=types;};
    
    叠加的主模板保留为空,默认参数提取可叠加的类型参数:

    template<class S, class Args=extract_args_from<Superposable, S>>
    class Superposition;
    
    template<class S, class Result, class...Parameters>
    class Superposition< S, types<Result, Parameters...>> {
    
    。顺便说一句,你错过了一个
    虚拟的


    请注意,我不赞成您的设计——结果应该是返回值(自然),使
    ()
    虚拟似乎是个坏主意(我会使用CRTP,如果我真的需要隐藏特定的实现,请键入erase)

    您可以删除
    supplicatable
    的主体,其工作原理如下:

    public:
      typedef Result result_t;
      void operator()(Result& result, const Parameters&...) const = 0;
    
    至少我建议你这么做

    下一步是彻底摆脱继承和推断
    参数

    class MyField {
    public:
      double operator()(const double& p1, const double& p2) const {
        return p1 + p2;
      }
    };
    template<typename S> // where S must be inherited from Superposable
    class Superposition {
      private:
        std::vector< std::shared_ptr<S> > elements;
    public:
    
      template<class...Parameters,
        class R=std::result_of_t<S&(Parameters const&...)>
      >
      R operator()(const Parameters&... parameters) const {
        R ret = {};
        for(auto p : elements){
          ret += (*p)(parameters...);
        }
        return ret;
      }
    };
    
    类MyField{
    公众:
    双运算符(){
    返回p1+p2;
    }
    };
    模板//其中S必须从Supplicatable继承
    类叠加{
    私人:
    std::vector元素;
    公众:
    模板
    R运算符()(常量参数和…参数)常量{
    R ret={};
    用于(自动p:元素){
    ret+=(*p)(参数…);
    }
    返回ret;
    }
    };
    
    它有完美转发的所有缺点,但也有所有的优点

    std::result\u of t
    是C++14,但在C++11中作为下拉菜单替换为
    typename std::result\u of::type

    模板
    
    template <typename Result, typename... Parameters>
    class Superposable
    {
    public:
        using result_t = Result;
        using params_t = std::tuple<Parameters...>;
    
        virtual void operator()(Result& result, const Parameters&...) const = 0;
    };
    
    class MyField : public Superposable<double, double, double>
    {
    public:
        void operator()(double& result, const double& p1, const double& p2) const
        {
            result = p1 + p2;
        }
    };
    
    template <typename, typename>
    class Superposition_impl;
    
    template <typename S, std::size_t... Is>
    class Superposition_impl<S, std::index_sequence<Is...>>
    {
        static_assert(std::is_base_of<Superposable<typename S::result_t, typename std::tuple_element<Is, typename S::params_t>::type...>, S>::value, "!");
    
    public:
        std::vector<std::shared_ptr<S>> elements;
    
        void operator()(typename S::result_t& result, const typename std::tuple_element<Is, typename S::params_t>::type&... parameters) const
        {
            for (auto p : elements)
            {
                typename S::result_t r;
                (*p)(r, parameters...);
                result += r;
            }
        }
    };
    
    template <typename S>
    using Superposition = Superposition_impl<S, std::make_index_sequence<std::tuple_size<typename S::params_t>::value>>;
    
    类可叠加 { 公众: 使用结果\u t=结果; 使用params_t=std::tuple; 虚空运算符()(结果和结果,常量参数和…)常量=0; }; 类MyField:公共可叠加 { 公众: void运算符()(双精度和结果、常数双精度和p1、常数双精度和p2)常数 { 结果=p1+p2; } }; 模板 类叠加; 模板 类叠加 { 静态断言(std::是::value,“!”)的基础; 公众: std::向量元素; void操作符() { 用于(自动p:元素) { typename S::result\u t r; (*p)(r,参数…); 结果+=r; } } }; 模板 使用叠加=叠加\u impl;

    感谢您的详细回答!当然,上面的Result和Parameters的double是更大对象的占位符,因此我希望避免按值返回。我显然需要更多地了解新的C++特性。你能推荐一些参考资料来阅读你使用的技巧吗?再次感谢。@SebastianBlatt按值返回几乎总是免费的,无论是实际的还是字面上的。要么通过省略(这只是很难保证),要么通过右值/移动构造函数(这几乎总是很容易)。它们是直接包含大型数组的类型吗?然后担心省略。否则,写一个move-ctor,并按值返回。
    public:
      typedef Result result_t;
      void operator()(Result& result, const Parameters&...) const = 0;
    
    class MyField {
    public:
      double operator()(const double& p1, const double& p2) const {
        return p1 + p2;
      }
    };
    template<typename S> // where S must be inherited from Superposable
    class Superposition {
      private:
        std::vector< std::shared_ptr<S> > elements;
    public:
    
      template<class...Parameters,
        class R=std::result_of_t<S&(Parameters const&...)>
      >
      R operator()(const Parameters&... parameters) const {
        R ret = {};
        for(auto p : elements){
          ret += (*p)(parameters...);
        }
        return ret;
      }
    };
    
    template <typename Result, typename... Parameters>
    class Superposable
    {
    public:
        using result_t = Result;
        using params_t = std::tuple<Parameters...>;
    
        virtual void operator()(Result& result, const Parameters&...) const = 0;
    };
    
    class MyField : public Superposable<double, double, double>
    {
    public:
        void operator()(double& result, const double& p1, const double& p2) const
        {
            result = p1 + p2;
        }
    };
    
    template <typename, typename>
    class Superposition_impl;
    
    template <typename S, std::size_t... Is>
    class Superposition_impl<S, std::index_sequence<Is...>>
    {
        static_assert(std::is_base_of<Superposable<typename S::result_t, typename std::tuple_element<Is, typename S::params_t>::type...>, S>::value, "!");
    
    public:
        std::vector<std::shared_ptr<S>> elements;
    
        void operator()(typename S::result_t& result, const typename std::tuple_element<Is, typename S::params_t>::type&... parameters) const
        {
            for (auto p : elements)
            {
                typename S::result_t r;
                (*p)(r, parameters...);
                result += r;
            }
        }
    };
    
    template <typename S>
    using Superposition = Superposition_impl<S, std::make_index_sequence<std::tuple_size<typename S::params_t>::value>>;