简体   繁体   中英

C++ functor (mapping)

I have created a class either<l, r> much like Haskell's Either ab . I have also implemented a function map directly in the class; this is what the code looks like:

template<typename l, typename r>
class either 
{
  template<typename b>
  either<l, b> map(const std::function<b (r)> &f)
  {
    // ...
  }
};

Now I want to isolate the map function in order to create an abstract base class called functor

template<typename a, template <a> class derived>
class functor
{
public:
  virtual ~functor();

  template<typename b>
  derived<b> map(const std::function<b (a)> &f) = nullptr;
};

either would inherit this class:

class either : functor<r, either<l, r>>

however this is invalid C++ as template member functions can not be virtual.

Moreover, I have attempted to test if <r, either<l, r>> can match <a, derived<a>> in functor<r, either<l, r>> (or any other template for that matter) but haven't been able to since it has two template parameters. Also note that other derived classes of functor might have different numbers of template arguments that are irrelevant to functor.

Can the functor base class be expressed in C++ templates?

Since you are using the curiously recurring template pattern, there's no need for virtual functions. Your goal of dispatching to the method of the derived class can be achieved directly from the base class.

A typical implementation would be the following :

#include <iostream>
#include <functional>

using namespace std;

template<typename a, class derived>
class functor
{
public:
    // You have to define the destructor
    virtual ~functor() {}

    template<typename b>
    // The full type of the derived class is known
    derived map(const std::function<b(a)> &f)
    {
        // Here you take advantage of the CRTP
        return static_cast<derived*>(this)->map(f);
    }
};

template<typename l, typename r>
// You have to put public as inheritance access level
class either : public functor<r, either<l, r>>
{ // The way you want to inherit implies that the base has no 
  // template template parameter, just template parameters !!
public:
    template<typename b>
    either<l, b> map(const std::function<b(r)> &f)
    {
        cout << "In derived" << endl;
        return  either<l, b>();
    }
};

int main() 
{
    // pointer to base class points to a derived object
    functor<int, either<int, int>> *ff = new either<int, int>();
    // map function will call the method of the derived class
    ff->map<int>([](int k){ return 1; });

    return 0;
}

I took the liberty of pointing some things out in the comments. HTH

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM