Virtual Template Function in C ++

I was looking for a way to use patterns and polymorphism at the same time. Here is a simplified version of my problem:

#include <iostream>
#include <vector>
using std::cout;
using std::endl;

//*******************************************************************
//*******************************************************************

struct DerivedStuff1
{
    static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};

struct DerivedStuff2
{
    static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};

//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
    template<typename StuffType> virtual void eval() const = 0;
};

class DerivedClass1 : public BaseClass
{
public:
    template<typename StuffType> virtual void eval() const
    {
        std::cout << "We are in DerivedClass1: ";
        StuffType::eval();
    }
};

class DerivedClass2 : public BaseClass
{
public:
    template<typename StuffType> virtual void eval() const
    {
        std::cout << "We are in DerivedClass2: ";
        StuffType::eval();
    }
};

int main()
{
    BaseClass* c1 = new DerivedClass1;
    c1->eval<DerivedStuff1>();
    c1->eval<DerivedStuff2>();

    BaseClass* c2 = new DerivedClass2;
    c2->eval<DerivedStuff1>();
    c2->eval<DerivedStuff2>();

    return 0;
}

This code does not compile, since in C ++ virtual template functions are not allowed. I found several approaches to solving this problem (CRTP, etc.), but none of them were really satisfactory. Is there an elegant way around this problem?

+4
source share
4 answers

. , , , , .

:

#include <iostream>

class DerivedStuff1 {
  public:
   static void eval() { std::cout << "Evaluating DerivedStuff1\n"; }
};

class DerivedStuff2 {
  public:
   static void eval() { std::cout << "Evaluating DerivedStuff2\n"; }
};

class DerivedClass1; class DerivedClass2;
class BaseClassVisitor {
  public:
    virtual void visit(DerivedClass1&) = 0;
    virtual void visit(DerivedClass2&) = 0;
};

class BaseClass {
  public:
    virtual void accept(BaseClassVisitor& v) = 0;
};

class DerivedClass1 : public BaseClass
{
  public:
    virtual void accept(BaseClassVisitor& v) { v.visit(*this); }
};

class DerivedClass2 : public BaseClass
{
  public:
    virtual void accept(BaseClassVisitor& v) { v.visit(*this); }
};


template <typename StuffType>
class EvalVisitor : public BaseClassVisitor
{
    virtual void visit(DerivedClass1&) {
        std::cout << "We are in DerivedClass1: ";
        StuffType::eval();
    }
    virtual void visit(DerivedClass2&) {
        std::cout << "We are in DerivedClass2: ";
        StuffType::eval();
    }

};

int main()
{
    EvalVisitor<DerivedStuff1> e1;
    EvalVisitor<DerivedStuff2> e2;

    BaseClass* c1 = new DerivedClass1;

    c1->accept(e1);
    c1->accept(e2);

    BaseClass* c2 = new DerivedClass2;

    c2->accept(e1);
    c2->accept(e2);

    return 0;
}

, .

+2

++ arent , .

#include <iostream>
#include <vector>
using std::cout;
using std::endl;

//*******************************************************************
//*******************************************************************

struct DerivedStuff1
{
    static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};

struct DerivedStuff2
{
    static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};

//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
    virtual void eval() const = 0;
};

template<typename StuffType>
class DerivedClass1 : public BaseClass
{
public:
    virtual void eval() const
    {
        std::cout << "We are in DerivedClass1: ";
        StuffType::eval();
    }
};

template<typename StuffType>
class DerivedClass2 : public BaseClass
{
public:
    virtual void eval() const
    {
        std::cout << "We are in DerivedClass2: ";
        StuffType::eval();
    }
};

int main()
{
    BaseClass* c1 = new DerivedClass1<DerivedStuff1>;
    c1->eval();
    c1 = new DerivedClass1<DerivedStuff2>;
    c1->eval();

    BaseClass* c2 = new DerivedClass2<DerivedStuff1>;
    c2->eval();
    c2 = new DerivedClass2<DerivedStuff2>;
    c2->eval();

    // deletes

    return 0;
}

We are in DerivedClass1: evaluating DerivedStuff1
We are in DerivedClass1: evaluating DerivedStuff2
We are in DerivedClass2: evaluating DerivedStuff1
We are in DerivedClass2: evaluating DerivedStuff2
+1

( ) ( ). .

, . , :

//*******************************************************************
//*******************************************************************

struct InterfaceStuff{
  virtual void eval() = 0;
}

struct DerivedStuff1 : public InterfaceStuff
{
    void eval() { cout << "evaluating DerivedStuff1" << endl; }
};

struct DerivedStuff2 : public InterfaceStuff
{
    void eval() { cout << "evaluating DerivedStuff2" << endl; }
};

//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
    virtual void eval(InterfaceStuff* interface) const = 0;
};

class DerivedClass1 : public BaseClass
{
public:
    virtual void eval(InterfaceStuff* interface) const
    {
        std::cout << "We are in DerivedClass1: ";
        interface->eval();
    }
};

class DerivedClass2 : public BaseClass
{
public:
    virtual void eval(InterfaceStuff* interface) const
    {
        std::cout << "We are in DerivedClass2: ";
        interface->eval();
    }
};

, :

struct DerivedStuff1
{
    static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};

struct DerivedStuff2
{
    static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};

//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
    template<typename Eval,typename StuffType> void eval() const
    {
        Eval::eval();
        StuffType::eval();
    }
};

class DerivedClass1 : public BaseClass
{
};

class DerivedClass2 : public BaseClass
{
};

, .

+1

vtable . , , .

:

#include <map>
#include <iostream>

class Base {
public:
  typedef void (Base::*eval_ptr)();
  using eval_vtable = std::map<std::type_index, eval_ptr>;

  Base(eval_vtable const& eval_p) : eval_ptrs(eval_p) {}

  template<typename T>
  void eval() {
    auto handler = eval_ptrs.find(type_index(typeid(T)));
    if(handler != eval_ptrs.end()) {
      auto handler_ptr = handler->second;
      (this->*handler_ptr)();
    }
  }

  eval_vtable const& eval_ptrs;
};

class Derived : public Base {
public:
    Derived()
     : Base(eval_functions) {}

  template<typename T>
  void eval_impl() {
    std::cout << typeid(T).name() << "\n";
  }

  static eval_vtable eval_functions;
};

Base::eval_vtable Derived::eval_functions = {
  { type_index(typeid(int)), eval_ptr(&Derived::eval_impl<int>) },
  { type_index(typeid(float)), eval_ptr(&Derived::eval_impl<float>) },
  { type_index(typeid(short)), eval_ptr(&Derived::eval_impl<short>) },
};

int main(int argc, const char* argv[]) {
  Derived x;
  Base * x_as_base = &x;

  x_as_base->eval<int>(); // calls Derived::eval_impl<int>()
  return 0;
}

, , .

: , - . , . , , .

+1

Source: https://habr.com/ru/post/1684331/


All Articles