C++11 variadic template + inheritance

I would like to write an abstraction of linear superpositions using variadic templates. To do that, I would like to define a base type that exhibits a certain form of operator() like so

template <typename Result, typename... Parameters>
class Superposable {
  public:
    typedef Result result_t;
    void operator()(Result& result, const Parameters&...) const = 0;
};

then inherit from it for the current problem, for instance like so

class MyField : public Superposable<double, double, double> {
  public:
    void operator()(double& result, const double& p1, const double& p2) const {
      result = p1 + p2;
    }
};

And I would then like to write an abstract base class that can form linear superpositions and gets the Superposable-derived class as a template parameter to determine the call signature of operator(). I would like to have something like

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;
       }
    }
};

Here are my questions:

  1. How do I read out the type information from the Superposable-derived class to define my operator() in Superposition?
  2. Also, is there a recommended way to enforce that Superposition can only be called with a Superposable-derived class as an argument?
  3. An even nicer solution would of course be to write a Superposition class that does not require MyField to be derived from a base class, but directly parses MyField's operator(). Can I do this somehow?

Thanks for your help!

Answers


First, a solution to your problem directly.

Some metaprogramming boilerplate:

template<class...>struct types{using type=types;};

A hana-style function that extracts the types of an argument, optionally taking a template from which to do the extraction based on:

template<template<class...>class Z, class...Args>
constexpr types<Args...> extract_args( Z<Args...> const& ) { return {}; }

An alias that wraps the above in a decltype for ease of use:

template<template<class...>class Z, class T>
using extract_args_from = decltype( extract_args<Z>( std::declval<T>() ) );

The primary template of Superposition is left empty, with a default argument that extracts the type arguments of Superposable:

template<class S, class Args=extract_args_from<Superposable, S>>
class Superposition;

then a specialization that gets the Result and Parameters types of the (possibly base class of) S's Superposable:

template<class S, class Result, class...Parameters>
class Superposition< S, types<Result, Parameters...>> {

live example. Btw, you missed a virtual.


Note that I don't approve of your design -- the result should be the return value (naturally), making () virtual seems like a bad idea (I'd use CRTP instead, and type-erase if I really need to hide the particular implementation).

You can remove the body of Superposable and it works as-is:

public:
  typedef Result result_t;
  void operator()(Result& result, const Parameters&...) const = 0;

which I'd recommend at the least.

The next step is to get rid of inheritance and deducing Parameters at all:

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;
  }
};

which has all the flaws of perfect forwarding, but all the advantages as well.

std::result_of_t<?> is C++14, but replace it with typename std::result_of<?>::type in C++11 as a drop-in.


Need Your Help

SVN - commit only some changes

svn

One of the things I like about GIT is that you can commit only some changes in a file. For example if you were doing two different changes which involved the same file, you can commit the file as two

How do I handle Facebook responses correctly?

android facebook

I am using the standard API provided by Facebook.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.