Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will concepts lite change the need of CRTP to achieve static polymorphism?

Since I have discovered CRTP some years ago, I use it in many places to achieve compile-time polymorphism for very intensive computing oriented codes. It's great to "inject" member functions into classes in a generic way when one cares about both genericity and maximal performances at runtime.

I have read/watch several things on the concepts lite which will be (I hope) a part of the next C++ standard. It will be absolutely wonderfull to design functions in a more abstract and generic manner, avoiding the awfull lines of SFINAE/std::enable_if I currently use.

I have not tested the g++ branches that implements concepts to play with them and to investigate metaprogramming methods I like in a new way. But maybe some of you have. My first thought is that concepts will not solve the problem of static polymorphism, but as these kind of things may heavily relies on tricks, I may be wrong. So my question is the following: will the concepts lite be able to achieve compile-time polymorphism (as we currently can do through CRTP) in a more convenient way ? (examples of code are welcome).

like image 528
Vincent Avatar asked Dec 20 '22 21:12

Vincent


2 Answers

I shouldn't think so. Concepts Lite will replace your use of enable_if, but I'm not sure that it allows for new techniques for CRTP. On the other hand, there may be some interesting things that can be done.

I will say that I ran into some CRTP issues with an earlier implementation of concepts lite. Checking constraints requires the type arguments to be complete types. If you have a base class parameterized over a derived class, you need to defer the check until the point of use. For example:

template<Fooable D>
struct crtp {
  void f() {
    static_cast<D*>(this)->g();
  }
};

struct derived : crtp<derived> { // Error!
};

When you try to check Fooable<derived>, derived won't have been defined yet. Better to write it this way:

template<typename D>
struct crtp {
  void f() requires Fooable<D>() {
    static_cast<D*>(this)->g();
  }
};

Now, Fooable<D>() is only checked when f() is called.

Just an FYI.

like image 70
Andrew Sutton Avatar answered Dec 22 '22 11:12

Andrew Sutton


So my question is the following: will the concepts lite be able to achieve compile-time polymorphism (as we currently can do through CRTP) in a more convenient way ? (examples of code are welcome).

No - they would not suppress CRTP in general. Concepts lite are mostly about ease of overloading and defining generic functions, plus ease of syntactic checks:

template<typename T>
concept bool EqualityComparable()
{
    return requires(T a, T b)
    {
        bool = {a == b};
        bool = {a != b};
    };
}

template<InputIterator I, EqualityComparable T>
I find(I first, I last, T x);
// or
template<InputIterator I>
I find(I first, I last, EqualityComparable x);

I think concepts lite would suppress many use cases of std::enable_if.

CRTP has different use cases, some of them are related to overloading indeed, for example:

template<typename Derived>
void do_something(const CRTP_Base<Derived> &x);

But CRTP is not limited to overloading, it has other applications: for example main use case for std::enable_shared_from_this does not imply any overloading:

class Widget : std::enable_shared_from_this<Widget>
{
    // ...
};

Some of use cases of CRTP involve even virtual functions - for instance automatic implementation of Cloneable interface:

// Simple example, no covariance, etc
struct Base
{
    typedef unique_ptr<Base> Unique;

    virtual Unique clone() const = 0;
    virtual ~Base() = default;
};

template<typename Derived>
struct ImplementCloneable: protected Base
{
    Unique clone() const override
    {
        return Unique(new Derived(static_cast<const Derived&>(*this)));
    }
protected:
    ~ImplementCloneable() = default;
};

struct Widget: ImplementCloneable<Widget>
{
};
like image 32
Evgeny Panasyuk Avatar answered Dec 22 '22 11:12

Evgeny Panasyuk