Not variadic expression templates

At the Kona committee meeting, it was voted (by someone, probably LEWG, I forget the story, I wasn’t in the room) to eliminate the overloaded operator() from C++2a std::span. Now it has only operator[].

The overloaded operator() was there merely for consistency with std::mdspan, which isn’t slated for C++2a.

std::mdspan needed an overloaded operator() because it couldn’t use overloaded operator[] because operator[] is a purely binary operator: s[a] means s.operator[](a), but s[a,b] means s.operator[]((a,b)) which means the same thing as s.operator[](b) because that’s what the comma operator does.

According to the minutes of the Kona meeting (again I wasn’t in the room), Corentin Jabot’s P1161R2 “Deprecate uses of the comma operator in subscripting expressions” (October 2018) was forwarded to CWG for inclusion in C++2a. This is great news!

Because the next thing that could happen, after a period of deprecation, is that C++2b might finally allow multi-argument operator[] overloads, the same way C++98 allowed multi-argument operator() overloads. Then mdspan (which is slated for C++2b) could use a multi-argument operator[]: you could index a single span as s[a] and a multi-dimensional mdspan as s[a,b]. (Of course then we’d really have to argue about whether C++ has multidimensional arrays or just single-dimensional arrays of arrays. I think the right answer is the latter. But anyway…)

Talking about multi-argument operator overloads over breakfast made me think up the following code snippet.

#include <type_traits>

struct A {
    int value = 0;
    A(int v): value(v) {}

    template<class... Ts,
             class = std::enable_if_t<(std::is_same_v<Ts, A> && ...)>>
    A operator+(Ts... ts) {
        return A((this->value + ... + ts.value));

A a = 1;
A b = a;
A c = a + b;
A d = a + b + c;
A e = a + b + c + d;

Here I’ve given A a variadic overloaded operator+ that accepts any number of A objects and adds them together using a C++17 fold-expression. And Clang is totally happy with this code.

But if your coworker wrote this code, hoping for some expression-templatey kind of thing, they’d be sadly mistaken! This example might make clearer what’s going on: we have here an operator+ that can accept a variadic number of parameters, but the compiler will never give it more than the usual two at a time. All we’ve done by making it variadic is we’ve permitted the same operator to be called as both a binary operator (a+b) and a unary operator (+a). There’s no such thing in C++ as a “ternary operator +”!

See also: the prefix-or-postfix-I-don’t-care increment operator.

Posted 2019-02-23