const directive in a method of a class

Hi all. Maybe my question is somewhat basic, I apologize in the case. I have coded the usual class for matrix manipulation. Following an example, I wrote:
1
2
3
4
5
  T& operator()(std::size_t row, std::size_t column)
  {
    if (not(row < nR and column < nC)) throw "ERROR operator()";
    return v[nC*row+column];
  }

which permits to access the private vector v, inside the class, with a two indices notation (i,j). Then I have, say,:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  unique_ptr<matrix<T>> operator*(matrix<T> & m)
  {
    if (nC != m.sizeR()) throw "ERROR operator*";
     
    unique_ptr<matrix<T>> result(new matrix<T>(nR, m.sizeC()));
    
    for (size_t r=0; r<nR; r++)
      for (size_t c=0; c<m.sizeC(); c++)
      {
        for (size_t k=0; k<nC; k++)
        {
          (*result)(r,c) += (*this)(r,k) * m(k,c);
        }
      }                       
    return result;
  }


Everything works fine, but I don't understand why it doesn't compile if I declare:

1
2
3
4
5
6
7
8
  unique_ptr<matrix<T>> operator*(matrix<T> & m) const
  {
  // ...

// error: 
// passing 'const matrix<double>' as 'this' argument of 'T& matrix<T>::operator()
// (std::size_t, std::size_t) [with T = double; std::size_t = unsigned int]'
// discards qualifiers [-fpermissive]) 


or if I declare
1
2
3
4
5
6
7
8
  unique_ptr<matrix<T>> operator*(matrix<T> const& m) 
  {
  // ...

// error: 
// passing 'const matrix<double>' as 'this' argument of 'size_t matrix<T>::sizeR()
// [with T = double; size_t = unsigned int]' 
// discards qualifiers 
Your operator() is not const, so you cannot call it on a non-const matrix. You may want to make another version of your operator() that is const and returns a const reference.
Thank you Zhuge, I'm starting understanding the problem. On the other hand, to use the operator() so that I can assign a value to the element of the matrix...

mx(3,5) = 12.34;

...operator() must be non-const, or am I wrong? hence operator* must stay non-const too, is it right?
Last edited on
You can overload const and non-const functions - they are considered different things. This is often done with subscript operators, for 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
// Example integer vector
class IntVec {
    public:
        // constructors, functions, etc.
        int& operator[] (std::size_t pos) {
            return this->_data[pos];
        }

        const int& operator[] (std::size_t pos) const {
            return this->_data[pos];
        }

    private:
        int *_data;
};

// calling:
IntVec v = /* ... */;
cout << v[10];
v[10] = 5;

const IntVec cv = /* ... */;
cout << cv[10];
cv[10] = 5; // ERROR: modifying a const reference 
this is another surprise. I thought that the operator functions couldn't be overloaded within a class! Thank you so much NT3 (& Zhuge: only now I have understood what you meant!).
---
I did this way

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
  T& operator()(std::size_t row, std::size_t column)
  {
    if (not(row < nR and column < nC)) throw "ERROR: operator()";
    return v[nC*row+column];
  }

  T const& operator()(std::size_t row, std::size_t column) const
  {
    if (not(row < nR and column < nC)) throw "ERROR: operator()";
    return (*this)(row, column);              //v[nC*row+column];
  }

  unique_ptr<matrix<T>> operator*(matrix<T>& m) const
  {
    if (nC != m.sizeR()) throw "ERROR operator*";
     
    unique_ptr<matrix<T>> result(new matrix<T>(nR, m.sizeC()));
    
    for (size_t r=0; r<nR; r++)
      for (size_t c=0; c<m.sizeC(); c++)
      {
        for (size_t k=0; k<nC; k++)
        {
          (*result)(r,c) += (*this)(r,k) * m(k,c);
        }
      }                       
    return result;
  }

and everything works. But still, if I declare

1
2
3
  unique_ptr<matrix<T>> operator*(matrix<T> const& m) const
  {
  // ... 


it doesn't compile.
error: passing 'const matrix<double>' as 'this' argument of 'size_t matrix<T>::sizeR() [with T = double; size_t = unsigned int]' discards qualifiers [-fpermissive]

Last edited on
You can overload an operator with whatever types you like, if that is what you are asking. They are exactly the same as functions - it just so happens that there are 'shortcut' ways of calling them. Here is a good little bunch of questions and answers on operator overloading which should help get you sorted: http://isocpp.org/wiki/faq/operator-overloading
Thank you NT3. In the recent past I have tried to overload some operator functions, but the compiler gave me some errors. I thought wrongly that it wasn't allowed to overload them, and I didn't study the issue further, silly of me.
---
Said that, I still don't understand why I cannot compile my class if I declare the passed matrix as 'const'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
unique_ptr<matrix<T>> operator*(matrix<T> const& m) const
  {
    if (nC != m.sizeR()) throw "ERROR operator*";
     
    unique_ptr<matrix<T>> result(new matrix<T>(nR, m.sizeC()));
    
    for (size_t r=0; r<nR; r++)
      for (size_t c=0; c<m.sizeC(); c++)
      {
        for (size_t k=0; k<nC; k++)
        {
          (*result)(r,c) += (*this)(r,k) * m(k,c);
        }
      }                       
    return result;
  }


Last edited on
Ah, I see now - this operator doesn't appear to be part of the matrix class you specified. The errors will be using 'const' on a non-class function. Add it in to the class you want it to be part of:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template <typename T>
class matrix {
    public:
        // ...

        unique_ptr<matrix<T>> operator*(matrix<T> const& m) const;

    private:
        // ...
};

// ...

template <typename T>
unique_ptr<matrix<T>> operator* (matrix<T> const& m) const {
    // ...
}

Last edited on
Thank you, but unfortunately they are already part of the class

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
template <typename T>
class matrix{
public:

  // ...

  T& operator()(std::size_t row, std::size_t column)
  {
    if (not(row < nR and column < nC)) throw "ERROR: operator()";
    return v[nC*row+column];
  }

  T const& operator()(std::size_t row, std::size_t column) const
  {
    if (not(row < nR and column < nC)) throw "ERROR: operator()";
    return (*this)(row, column);              //v[nC*row+column];
  }

  // ...
  
  unique_ptr<matrix<T>> operator*(matrix<T> const& m) const
  {
    if (nC != m.sizeR()) throw "ERROR operator*";
     
    std::unique_ptr<matrix<T>> result(new matrix<T>(nR, m.sizeC()));
    
    for (size_t r=0; r<nR; r++)
      for (size_t c=0; c<m.sizeC(); c++)
      {
        for (size_t k=0; k<nC; k++)
        {
          (*result)(r,c) += (*this)(r,k) * m(k,c);
        }
      }                       
    return result;
  }

 //...

private:
  std::size_t nR; // n rows
  std::size_t nC; // n columns
  std::vector<T> v;
};  
Oh, I missed your last edit. You need to set your 'sizeR' and 'sizeC' methods to be const as well.
thank you so much! what an idiot I was, it seems so evident now!
Topic archived. No new replies allowed.