1

Consider the following code:

struct Base
{
    ~Base() {}
    virtual double operator()(double x) const = 0;
};

template<typename F, typename G> struct Compose;  //forward declaration of Compose

struct Derived1 : public Base    //plus many more derived classes
{
    virtual double operator()(double x) const {return x;}
    template <typename F>
    Compose<Derived1,F> operator()(const F& f) const {return Compose<Derived1,F>(*this,f);}
};

template<typename F, typename G>
struct Compose : public Base
{
     Compose(const F &_f, const G &_g) : f(_f), g(_g) {}
     F f;
     G g;
     virtual double operator()(double x) const {return f(g(x));}
};

void test()
{
    Derived1 f,g;
    auto h=f(g);
}

The class compose here takes two derived classes f,g and returns the compositum f(g(x)) via operator().

Is it somehow possible to avoid the explicit definition in each of the many derived classes, and add a function in the base class?


EDIT: To explain better what I am looking for: In principle, I want to add something like the following in the base class

template<typename F> Compose<decltype(*this), F>
operator()(const F& f) {return Compose<decltype(*this), F>(*this,f);}

I tried this in the hope that decltype(*this) automatically inserts the type of the derived class. But it doesn't seem to work like this...


Solution: I finally encountered the way to do it, and that is via CRTP. The Base class then takes the form

template<typename Derived>
struct Base
{
    ~Base() {}
    virtual double operator()(double x) const = 0;

    template<typename F> Compose<Derived, F>
    operator()(const F& f) {return Compose<Derived, F>(static_cast<Derived const&>(*this),f);}
};

and the derived classes are derived from

struct Derived1 : public Base<Derived1>
davidhigh
  • 12,239
  • 1
  • 34
  • 64
  • It would be helpful if we started with code that *compiled*, yet doesn't do what you want. The first source fails at this (for a plethora of reasons), as does the second, thereby making it difficult to enter into this question much less pony viable alternatives. (and `Compose` isn't a function; it looks like a template class, but currently its not even that). – WhozCraig Apr 21 '14 at 21:53
  • You're right. I'll update it in a few minutes (a few commas here and there ;-)). – davidhigh Apr 21 '14 at 22:04
  • Done. Compiles in MSVC 11. – davidhigh Apr 21 '14 at 22:16
  • Not included as an answer since it divests from the virtual model you seem to be seeking, but you may also consider static polymorphism with CRTP as an option ([**See it live**](https://ideone.com/TroYIb)). It may surprise you. – WhozCraig Apr 24 '14 at 03:03

2 Answers2

1

Your Base class is pure abstract, as such you can't do that. You could define your Base class as a concrete class, and then define the overloaded function call operator in the concrete Base class. Please see code below:

struct Base
{
    ~Base() {}
    virtual double operator()(double x) const {return x;}
};

struct Derived1 : public Base    //plus many more derived classes
{

};

int main()
{
  Derived1 d;
  double x = d(1);
  std::cout << x << std::endl;

  return 0;
}
101010
  • 39,010
  • 10
  • 84
  • 149
  • hmmm ... thanks, but this is trivial. I've edited my question so that it becomes more clear what I want. – davidhigh Apr 21 '14 at 21:42
1

Given that your Base is pure virtual one can move the template function to the Base. All derived classes will have to implement the double operator()(double x) anyway and delegate.

Also I used a Base pointer instead of an instance because as you point out it would not work in the Compose struct otherwise (probably want to change the implementation there to make it less leak prone...).

Note that I took out the Compose from your hierarchy (looks like it could be used for a more general purpose) - feel free to put it back in (it would allow for endless composition).

Also I removed all the const because struct require supplied default CTOR for const objects (feel free to put those in).

And I renamed the composition operator because my compiler was being blinded by the other operator() in the client code.

It needs cleaning up the core is there:

template <typename F, typename G> struct Compose
{
     Compose( F* _f,  G &_g) : f(_f), g(_g) {}
      F* f;
     G g;
     double operator()(double x)  {return (*f)(g(x));}
};

struct Base
{
    ~Base() {}
    virtual double operator()(double x) = 0;
    template <typename F> Compose<Base,F> composeMeWith(F& f)  {return Compose<Base,F>(this,f);}    
};

struct D1 : public Base 
{
    virtual double operator()(double x)  { return 1.0; }
};

struct D2 : public Base 
{
    virtual double operator()(double x)  { return 2.0; }
};

some client code:

#include <iostream>
using namespace std;

int main(int argc, char** argv) 
{
     D1 d1;
     D2 d2;

    auto ret1 = d1.composeMeWith(d2);
    auto ret2 = d2.composeMeWith(d1);

    cout << ret1(100.0) << endl;
    cout << ret2(100.0) << endl;
}
Hans Roggeman
  • 2,300
  • 13
  • 31
  • Thanks a lot! The core is important, the rest (shared_ptr's or whatever) is trivial. I will test it tomorrow and accept (--hopefully :-D). – davidhigh Apr 21 '14 at 22:41
  • Thanks again, your proposed solution will work. But I'm curious if there is any alternative to the "pointer"-approach? I mean the task doesn't sound all to hard: a derived class simply needed to insert its own type template argument (this is what I tried with decltype(*this)...). Is this somehow possible using only a function defined in the base class? – davidhigh Apr 22 '14 at 15:01
  • I don't think you can refer to `this` in the template typenames (there is no `this` at that point). You can use it inside the `{}` though. Worth some investigation. – Hans Roggeman Apr 22 '14 at 21:36
  • @davidhigh The reason the `decltype` idea does not work is here: http://stackoverflow.com/questions/10424337/does-c11s-decltype-make-clone-unnecessary – Hans Roggeman Apr 23 '14 at 14:07