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>
4
  • 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). Commented Apr 21, 2014 at 21:53
  • You're right. I'll update it in a few minutes (a few commas here and there ;-)). Commented Apr 21, 2014 at 22:04
  • Done. Compiles in MSVC 11. Commented Apr 21, 2014 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). It may surprise you. Commented Apr 24, 2014 at 3:03

2 Answers 2

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;
}
Sign up to request clarification or add additional context in comments.

4 Comments

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).
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?
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.
@davidhigh The reason the decltype idea does not work is here: stackoverflow.com/questions/10424337/…
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;
}

1 Comment

hmmm ... thanks, but this is trivial. I've edited my question so that it becomes more clear what I want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.