Как сказал Билли, вы не можете перегружать операторов. Однако вы можете очень близко подходить к тому, что вы хотите, с помощью «обычной» перегрузки операторов (и, возможно, некоторого метапрограммирования шаблона). Было бы довольно легко учесть что-то вроде этого:
#include <iostream>
class FakeNumber {
int n;
public:
FakeNumber(int nn) : n(nn) {}
operator int() const { return n; }
};
class Range {
int f, t;
public:
Range(const int& ff, const int& tt) : f(ff), t(tt) {};
int from() const { return f; }
int to() const { return t; }
};
Range operator-(const FakeNumber& a, const int b) {
return Range(a,b);
}
class Matrix {
public:
void operator()(const Range& a, const Range& b) {
std::cout << "(" << a.from() << ":" << a.to() << "," << b.from() << ":" << b.to() << ")" << std::endl;
}
};
int main() {
FakeNumber a=1,b=2,c=3,d=4;
Matrix m;
m(a-b,c-d);
return 0;
}
Недостатком является то, что это решение не поддерживает общелитеральные выражения. Либо из, либо должны быть пользовательскими классами, поскольку мы не можем перегрузить оператор для двух примитивных типов.
Вы также можете перегрузить operator*
, чтобы разрешить указывать пошаговый режим, например:
m(a-b*3,c-d); // equivalent to m[a:b:3,c:d]
И перегрузить обе версии operator--
, чтобы пропустить одну из границ:
m(a--,--d); // equivalent to m[a:,:d]
Другим вариантом является определение двух объектов, называемых чем-то вроде Matrix :: start и Matrix :: end, или как вам угодно, и затем вместо использования operator--
вы можете использовать их, а затем другая граница не будет должна быть переменной и может быть литералом:
m(start-15,38-end); // This clutters the syntax however
И вы, конечно, можете использовать оба способа.
Я думаю, что это лучшее, что вы можете получить, не прибегая к причудливым решениям, таким как настраиваемые инструменты предварительной сборки или неправильное использование макросов (в том виде, в котором Матье предлагал и не рекомендовал их использовать)