Initialize a matrix like in the Eigen library!

I am planning on writing a Matrix2d class which will be fun for me and help me get a better grasp on matrices in linear algebra.

The first thing I want to do is initialize the matrix and I would like to do it like the Matrix2d from the Eigenlibrary does:

1
2
3
4
5
6
  Matrix2d m;
m << 1, 2, 3,
     4, 5, 6,
     7, 8, 9;

std::cout << m;


How would I would tackle this task?? I know I have to use the operator<< but I don't know how. In fact I only know how use operator<< with ostream.

Thanks.
Last edited on
You would need to overload both operator<< and operator,
A simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <vector>

class Array {
    std::vector<int> v;
public:
    Array() = default;
    friend std::ostream& operator<<(std::ostream& out, const Array& a) {
        for (int n: a.v) out << n << ' ';
        return out;
    }
    friend Array& operator<<(Array& a, int n) {
        a.v.push_back(n);
        return a;
    }
};

Array& operator,(Array& a, int n) {
    return a << n;
}

int main() {
    Array a;
    a << 1, 2, 3, 4, 5;
    std::cout << a << '\n';
}

Last edited on
@dutch

Wow, didn't know exited an operator, in C++.

Thank you very much.
Hey,

The code above works fine inside main.cpp, but when I put the class in a header file it throws an error:

multiple definition of `operator,(Array&, int)'

It says it was first defined in a file 'vector.tcc'.
Seems unlikely, doesn't it.
You need to give more detail.
A complete program that demonstrates the problem, as simple as possible.
What system and compiler are you using?
What is the compile line?
The compiler I am using is a MinGW distro version 17.1 thant currently contains GCC 9.2.0 and Boost 1.71.0, downloaded from here https://nuwen.net/mingw.html

My enviroment is codeblocks.

header file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Array {
    std::vector<int> v;
public:
    Array() = default;
    friend std::ostream& operator<<(std::ostream& out, const Array& a) {
        for (int n: a.v) out << n << ' ';
        return out;
    }
    friend Array& operator<<(Array& a, int n) {
        a.v.push_back(n);
        return a;
    }
};

Array& operator,(Array& a, int n) {
    return a << n;
}


 
c:\gcc\mingw\include\c++\9.2.0\bits\vector.tcc|426|multiple definition of `operator,(Array&, int)'; 


line 426 in vector.tcc

Last edited on
Hey I solved the problem

What I did was declare the function Array& operator,(Array& a, int n) as Array friend function and it worked ok.

header file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 class Array {
    std::vector<int> v;
public:
    Array() = default;
    friend std::ostream& operator<<(std::ostream& out, const Array& a) {
        for (int n: a.v) out << n << ' ';
        return out;
    }
    friend Array& operator<<(Array& a, int n) {
        a.v.push_back(n);
        return a;
    }
     friend Array& operator,(Array& a, int n) {
    return a << n;
}

};
Last edited on
It still makes no sense to me.
Why would operator,(Matrix&, int) conflict with operator,(Array& a, int n)?
And what is something called Matrix doing in the standard library?

Anyway, considering how you fixed it, another possibility might be to leave it outside the class but make it inline, since it doesn't need to be a friend.
The problem is also that comma delimiting is OK but the structure is lost by the return at the end of the line.

ie typing in the following for a 2 X 3 matrix:
1,2,3
4,5,6 - is ideal but hard to achieve. For my own purposes I am keen to see a solution. Even adding 2, 3 would be good. Maybe a (albeit messy) constructor that asks for the next line/row?
@dutch

Sorry, The error line is wrong, I have edited the post.

the correct error line is this one:

c:\gcc\mingw\include\c++\9.2.0\bits\vector.tcc|426|multiple definition of `operator,(Array&, int)'

operator,(Array&, int) is not from the STL it is in in the header file.

The line in vector.tcc is as follows:

1
2
void vector<_Tp, _Alloc>::
      _M_realloc_insert(iterator __position, _Args&&... __args)
is not from the STL it is in in the header file.

But surely vector.tcc is defining the std::vector class for the standard library. The line you show has no relation to operator, or Array or anything. None of this makes sense to me. And I can't recreate the problem (although you haven't shown the complete program that you are trying to compile).
It doesn't make sense to me neither.

here is the full program.

header.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <vector>
#include <fstream>

class Array
{
    std::vector<int> v;
public:
    Array() = default;
    friend std::ostream& operator<<(std::ostream& out, const Array& a)
    {
        for (int n: a.v) out << n << ' ';
        return out;
    }
    friend Array& operator<<(Array& a, int n)
    {
        a.v.push_back(n);
        return a;
    }
};

Array& operator,(Array& a, int n)
{
    return a << n;
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include "header.h"

using namespace std;

int main()
{
    Array a;

    a << 1, 2, 3, 4, 5;

    cout << a;
}
I can't recreate the problem. Just one last test and I'll let it go. I was hoping someone like JLBorges might have an idea as to what's happening.

Try the following for header.h. I think the important change that might fix the problem (as making the function an in-class friend did) is adding inline. I also added include guards since every header file should have those (or #pragma once ).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef ARRAY_H_     // include guards
#define ARRAY_H_

#include <vector>
#include <ostream>   // used to be fstream

class Array
{
    std::vector<int> v;
public:
    Array() = default;
    friend std::ostream& operator<<(std::ostream& out, const Array& a)
    {
        for (int n: a.v) out << n << ' ';
        return out;
    }
    friend Array& operator<<(Array& a, int n)
    {
        a.v.push_back(n);
        return a;
    }
};

inline Array& operator,(Array& a, int n)   // added inline
{
    return a << n;
}

#endif 

It seems that overloaded comma initializer's are not good form. Some write they are/can be unreliable and point to the std::initializer_list as a reliable alternative.

So, on that note:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <vector>

int main()
{
    std::initializer_list<int> init_list;
    
    init_list =
    {
        1,2,3,
        4,5,6,
        7,8,9
    };
    
    std::vector<int> vec{init_list};
    
    for (auto it:vec)
        std::cout << it << ' ';
    
    std::cout << '\n';
}


1 2 3 4 5 6 7 8 9 
Program ended with exit code: 0
Last edited on
Gets close, 'there' with a bit of fine tuning.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include <vector>
#include <valarray> // <array> DOESN'T ACCEPT AN INITIALIZER LIST

class Matrix
{
public:
    int m_rows;
    int m_cols;
    
    std::vector<double> m_vec;
public:
    Matrix(int r, int c){m_rows = r; m_cols = c;}
    Matrix(int r, int c, std::initializer_list<double> list)
    {
        m_rows = r; m_cols = c; // CHECK HERE FOR SIZE OF LIST
        m_vec.clear();
        for(auto it:list)       // 2D vs 1D VECTOR
            m_vec.push_back(it);
    }
    
    ~Matrix(){};
    
    friend std::ostream& operator<< (std::ostream& out, Matrix& m)
    {
        for(auto iter :m.m_vec)
            out << iter << ' ';
        out << '\n';
        
        return out;
    }
    
};

int main()
{
    std::initializer_list<int> init_list;
    
    init_list =
    {
        1,2,3,
        4,5,6,
        7,8,9
    };
    
    std::cout << "VECTOR\n";
    std::vector<int> vec{init_list};
    for (auto it:vec)
        std::cout << it << ' ';
    std::cout << "\n\n";
    
    std::cout << "VALARRAY\n";
    std::valarray<int> arr(init_list);
    for (auto it:arr)
        std::cout << it << ' ';
    std::cout << "\n\n";
    
    std::cout << "MATRIX\n";
    Matrix m(3,3,  // PROBABLY CAN AVOID THIS BY INITIALLY DECLARING MATRIX(r,c)
    {
        1,2,3,
        4,5,6,
        7,8,9
    } );
    
    std::cout << m;
    
    return 0;
}
Thank you @dutch for all, programming community appreciates people like you.

@againtry, std::initializer_list seems to be a nice option, I will be sure to check it out. Thank you
Topic archived. No new replies allowed.