Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ - matrix initialization with comma-separated values

Tags:

c++

Hi I came across this piece of code. It demonstrates how to work with matrix structures of the dlib library.

According to this one can initialize a matrix structure by:

M = 54.2,  7.4,  12.1,
    1,     2,    3,
    5.9,   0.05, 1;

How can this be possible in C++?

Is this some kind of operator overloading?

like image 226
Nfys Avatar asked May 28 '15 13:05

Nfys


1 Answers

Logic

This is possible by overloading operator, (operator comma), and for example make it push new floating point values into M.

A thing to notice is that operator, should always have at least one parameter of class type, therefore you'll have to create a class that is implicitly convertible to floating point value (for example via a non explicit constructor with 1 argument of type double or float).

Example

For example we'll try to do this for a wrapper type over an std::vector and we'll try to make M = 1, 2, 3, 4, 5 a valid expression which results in an std::vector with those elements in sequence. You'll see that this is easily applicable to the matrix example you gave.

A thing to remember is that operator= has more precedence over operator, (as shown in this table of operator precedence); therefore M = 1, 2, 3, 4, 5 will really be parsed as: (((((M = 1), 2), 3), 4), 5).

Given that, we'll start by creating our class container with an operator= that takes a single value and pushes it into the container:

template<typename ValueType>
struct container {
    
    explicit container(std::size_t n) {
        vec.reserve(n);
    }
    
    container& operator=(ValueType a) {
        vec.push_back(a);
        return (*this);
    }

    std::vector<ValueType> vec;
    
};

At this point we can define operator, as:

template<typename ValueType>
container<ValueType>& operator,(container<ValueType>& m, ValueType a) {
    m.vec.push_back(a);
    return m;
}

which just pushes back a new element value.

And now you can easily see that the following works just fine and prints 1 2 3 4 5:

int main() {
    container<int> M(5);
    M = 1, 2, 3, 4, 5;
    for (auto i : M.vec) std::cout << i << ' ';
}

Live demo

Considerations

I discourage this technique as much as possible. It forces you to have weird semantic for other operators, such as operator= and really seem to add nothing to a simple use of std::initializer_list<T>.

A saner example would be to have operator= as follows:

container& operator=(std::initializer_list<ValueType> a) {
    std::copy(begin(a), end(a), back_inserter(vec)); 
    return (*this);
}

and then simply use brackets:

int main() {
    container<int> M(5);
    M = { 1, 2, 3, 4, 5 };
    for (auto i : M.vec) std::cout << i << ' ';
}

Live demo

like image 138
Shoe Avatar answered Sep 21 '22 20:09

Shoe