I would like to propose new separator for arguments as shown below:

void func(int a; int b);  // not "," but ";"

The motivation to add this feature is that multidimensional subscript operator in P2128R3 ( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2128r3.pdf ) may cause confusion.
If subscript operator could take multiple arguments, there could be two types of usages.
The first usage is multidimensional access as explained in P2128R3 and the second one is subrange access as follows:

class MyVector {
    std::vector<int> vec;
    MyVector(std::vector<int>&& v) : vec(std::move(v)) {}

    MyVector operator[](int a, int b) const {  // returns subrange
        auto it = vec.begin();
        return MyVector(std::vector<int>(it + a, it + b));

I think this is confusing and probably occurs many bugs.
Thus, to make it clear at a glance will help avoiding bugs.  
My proposal is to rule implicitly that array[0, 1] should be a subrange access and array[0; 1] implies multidimensional access.
Then we can write as follows:

struct Matrix {
    float** m;

    Matrix operator[](int row_begin, int row_end;
                      int col_begin, int col_end) const {
        Matrix mat{.m = new float*[row_end - row_begin]};
        for (int i = row_begin; i < row_end; i++) {
            auto& dst = mat.m[i - row_begin];
            dst = new float[col_end - col_begin];
            std::copy(m[i] + col_begin, m[i] + col_end, dst); 
        return mat;

void func(const Matrix& mat) {
    // cut out 4 elements [1,4], [1,5], [2,4] and [2,5] from mat
    Matrix m = mat[1, 3; 4, 6];  

And this proposal also solve the problem of multiple variadic template parameters.

template<typename... T, typename... U>
void f1(T... t, U... u);  // error: Currently, we cannot do this without std::tuple

template<typename... T, typename... U>
void f2(T... t; U... u);  // OK

f2(1, 2.0; 3.f, 4L);  // f2(int, double; float, long)
f2(1; 2.0, 3.f, 4L);  // f2(int; double, float, long) different signature from above
f2( ; );              // this is also OK. f2(void; void)
f2();                 // error: no matching function for f2(void)

I am also thinking about variadic arguments with the new separator.

template<typename... T>
void f3(T t;...);

f3(1; 2; 3);   // f3(int; int; int)

template<typename... T, typename... U>
void f4(T t, U u;...);

f4(1, 2; 3, 4; 5, 6);  // f4(int, int; int, int; int, int)

template<typename... T>
void f5(T... t;...);

f5(1, 2, 3; 4, 5; 6);   // f5(int, int, int; int, int; int)
f5(1, 2, 3; ; );        // f5(int, int, int; void; void)


Yanagita Tatsuya