How to simplify this C++ CRTP example? I wanted a simple thing: being able to override a base class and just add one single getter. The bad thing is the base class does override some operators and will return the wrong type. I, therefore, came across the curiously recurring template pattern which helped me to write the following.
However, I am still not very satisfied. I wrote a very similar question here which helped me to learn about CRTP.
#include &lt;algorithm&gt;
#include &lt;array&gt;
#include &lt;iostream&gt;

using namespace std;

template &lt;typename C, typename T, int N&gt;
class PointCRTP
{
   protected:
    array&lt;T, N&gt; elements;

   public:
    PointCRTP() = default;
    PointCRTP(array&lt;T, N&gt; el) : elements(el) {}

    C operator+(C&amp; other)
    {
        C c;
        transform(elements.begin(), elements.end(), other.elements.begin(),
                  c.elements.begin(), plus&lt;int&gt;());
        return c;
    }

    T operator[](int k) { return elements[k]; }

    friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, C const&amp; x)
    {
        os &lt;&lt; &quot;P(&quot;;
        for (auto k : x.elements) os &lt;&lt; k &lt;&lt; &quot;, &quot;;
        return os &lt;&lt; &quot;\b\b&quot; &lt;&lt; ')';
    }
};

template &lt;typename T, int N&gt;
struct Point : public PointCRTP&lt;Point&lt;T, N&gt;, T, N&gt; {
    using PointCRTP&lt;Point&lt;T, N&gt;, T, N&gt;::PointCRTP;
};

template &lt;typename T&gt;
struct Point2D : public PointCRTP&lt;Point2D&lt;T&gt;, T, 2&gt; {
    Point2D() = default;
    Point2D(T x, T y) : PointCRTP&lt;Point2D&lt;T&gt;, T, 2&gt;({x, y}) {}

    T getX() { return PointCRTP&lt;Point2D&lt;T&gt;, T, 2&gt;::elements[0]; }
    T getY() { return PointCRTP&lt;Point2D&lt;T&gt;, T, 2&gt;::elements[1]; }
};

int main()
{
    Point&lt;int, 3&gt; p({1, 2, 3});
    Point&lt;int, 3&gt; q({3, 4, 2});
    Point&lt;int, 3&gt; c = p + q;
    std::cout &lt;&lt; c &lt;&lt; &quot; = &quot; &lt;&lt; p &lt;&lt; &quot; + &quot; &lt;&lt; q &lt;&lt; endl;

    Point2D&lt;int&gt; r(1, 2);
    Point2D&lt;int&gt; s(3, 4);
    Point2D&lt;int&gt; t = r + s;
    std::cout &lt;&lt; t &lt;&lt; &quot; = &quot; &lt;&lt; r &lt;&lt; &quot; + &quot; &lt;&lt; s &lt;&lt; endl;
}

Is there a way to make this example simpler (shorter)?
Avoid special cases
A lot of problems come from the fact that you have slightly different ways to construct a 2D point and to get its elements than you have for an arbitrary dimensional point. You should avoid that first, this will make your life much easier.
Here is a class Point that supports getX() and getY() with compile-time checking that the size of elements is large enough, and a constructor that takes a variable number of arguments, so you don't need to use braces when constructing a Point:
template &lt;typename T, int N&gt;
class Point
{
   std::array&lt;T, N&gt; elements;

public:
    template&lt;typename... E&gt;
    Point(E&amp;&amp;...e): elements({std::forward&lt;E&gt;(e)...}) {}

    Point operator+(const Point&amp; other)
    {
        Point c;
        std::transform(elements.begin(), elements.end(), other.elements.begin(),
                  c.elements.begin(), plus&lt;T&gt;());
        return c;
    }

    const T&amp; operator[](size_t k) const
    {
        return elements[k];
    }

    friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, Point const&amp; x)
    {
        os &lt;&lt; &quot;P(&quot;;
        for (auto&amp; k : x.elements) os &lt;&lt; k &lt;&lt; &quot;, &quot;;
        return os &lt;&lt; &quot;\b\b&quot; &lt;&lt; ')';
    }

    template&lt;std::enable_if_t&lt;(N &gt; 0), int&gt; = 0&gt;
    const T&amp; getX() const {
            return elements[0];
    }

    template&lt;std::enable_if_t&lt;(N &gt; 1), int&gt; = 0&gt;
    const T&amp; getY() const {
            return elements[1];
    }
};

There are various ways to enable/disable member functions at compile time, the above uses std::enable_if_t which completely disables a function. You can also use a compile-time assert, like so:
T getY() const {
    static_assert(N &gt; 1, &quot;this point doesn't have a y coordinate&quot;);
    return elements[1];
}

Although as pointed out in the comments, this has the drawback that you cannot check at compile time if a given Point type supports getX(), getY().
To make a Point2D convenience class, use using:
template&lt;typename T&gt;
using Point2D = Point&lt;T, 2&gt;;