c++templatespolymorphismvirtual-functionsfunction-templates

Is there any workaround for a virtual function template with a type constraint in this case?


If you have a concept and a class member function template like so:

template<typename T>
concept Vector2 = requires (T t) { t.x; t.y; };

struct Shape
{
    bool contains(const Vector2 auto&) { ... }
};

Is there any way, through some workaround, to have contains be a purely virtual function? So that child classes (e.g., Circle, Polygon, etc) can inherit like so:

struct Circle : public Shape
{
    bool contains(const Vector2 auto&) const override;
};

Obviously the above won't work since virtual function templates are not allowed. The reason for the Vector2 concept is that I use 2D functionality from different libraries and I want all their respective Vector2-classes to be able to be passed to my functions. Whether or not that design pattern itself is generally a good idea or not is not what my question is about, rather simply if something resembling what I want to achieve is possible.

I searched around a bit, and found an SO answer suggesting the Base Visitor pattern, but I struggle to see how I apply it here.

Is there any way to achieve something close to what I want, or is it just not possible?

(This is an altered and more specified version of a previous question of mine. I was told that more information and an actual example would be needed to give an answer.)


Solution

  • You might type erase the parameter of the template function.

    As you expect to call it with object from library, and so cannot change hierarchy, you might use Sean Parent pattern, something like:

    template <typename T>
    class Vector2View
    {
    private:
     struct IVector2 // internal erased type
     {
        virtual ~IVector2() = default;
        virtual T getX() const = 0;
        virtual void setX(T value) = 0;
        virtual T getY() const = 0;
        virtual void setY(T value) = 0;
     };
    
      template<typename U>
      struct Vector2T : IVector2 // Wrapper around given type
      {
        explicit Vector2T(U& u) : u(u) {}
        T getX() const override { return u.x; }
        void setX(T value) override { u.x = value; }
        T getY() const  override { return u.y; }
        void setY(T value) override { u.y = value; }
    
        U& u;
      };
    
    public:
      template <typename U>
      requires (Vector2<U>)
      /* implicit */ Vector2View(U& v) : ptr(std::make_unique<Vector2T<U>>(v)) {}
    
        T getX() const { return ptr->getX(); }
        void setX(T value) { return ptr->setX(value); }
        T getY() const { return ptr->getY(); }
        void setY(T value) { return ptr->setY(value); }
    
    private:
      std::unique_ptr<IVector2> ptr;
    };
    

    And then

    struct Shape
    {
        virtual ~Shape() = default;
        virtual bool contains(const Vector2View<double>&) const = 0;
    };
    

    Demo