4

I'm implementing a C++ expression templates library. I have set up a proper SubMatrixExpr class to collect elements within a matrix, enabling a syntax like

B = SubMatrix(A,1,3,2,10);

which is equivalent to Matlab's

B = A(1:3,2:10);

Of course, Matlab's syntax is much more confortable than mine. So my question is

Is there any possibility to set up Matlab's colon : operator in C++?

Thank you very much in advance.

Vitality
  • 20,705
  • 4
  • 108
  • 146
  • No. There is no colon operator in C++. However, you could overload some other operator to do it. – David May 02 '13 at 13:32
  • 3
    You will not be able to obtain the exact syntax you have in Matlab, but you could get closer by overloading the `operator()` of your `Matrix` class so that it takes two ranges as operands. You would then be able to write `B = A(range(1,3), range(2,10))`, which *may* be a bit more readable than the `SubMatrix` version. – Luc Touraille May 02 '13 at 13:40
  • @LucTouraille good hint for the `range()` part, I put that into my answer now. Thanks. – Arne Mertz May 02 '13 at 13:51
  • @LucTouraille Thanks. Your suggestion of implementing `Range` worked perfectly for me. – Vitality May 03 '13 at 08:02

2 Answers2

4

Short answer: no. The colon is not a valid C++ operator, so it cannot be overloaded. And if it could, it still would not be possible to achiev what you need easily, because it most surely would have precedence over the comma operator, which would make your expression be in the lines of A((1:3),(2:10)), and you are only allowed to overload operators if one of the operands is a user defined type (which is not the case here).

So even with any other operator in place, you could not do anything that looks like this.

What you can do: overload operator() for your matrix class, for sensible arguments. This could enable you to write something like B = A(1,3,2,10);, if you define an operator()(int,int, int, int);

My preferred solution would be an operator() taking either two initializer_lists in C++11 or two std::array<int,2>. The former would have to check that the list contains exactly two elements, the latter would need an awkward double brace for initialization - that might disappear in C++14 or later (N3526, but afaik it's not in the CD for C++14). Third possibility would of course be a named class that you could call, presenting a range:

class Matrix {
  /* ... */
public:
  Matrix operator()(std::initializer_list<int> range1, std::initializer_list<int> range2);
  //or:
  Matrix operator()(std::array<int,2> range1, std::array<int,2> range2);
  //or:
  Matrix operator()(Range range1, Range range2);

};

int main() {
  Matrix A;
  /* ... */
  Matrix B = A({1,3}, {2,10}); //beware of A({1,3,2,4,5}, {0}) !
  //or:
  Matrix B = A({{1,3}}, {{2,10}}); //uhgs...
  //or:
  Matrix B = A(Range(1,3), Range(2,10)); //more verbose, but also more understandable
}
Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
1

Another idea is to make the types of the arguments in the constructor char *, and then inside the constructor parse out the numbers from the :. For example,

A = B("3:4","8:end");

A = B(":","2");

This permits you to do more, like use the end keyword.

Thomas Fritsch
  • 9,639
  • 33
  • 37
  • 49
user166991
  • 11
  • 1
  • 1
    but it'll be inefficient because you need to parse the string, and `char*` is a bad idea for strings because you don't know the length before hand – phuclv Jun 09 '19 at 01:52