Mike Warren - 1 year ago 75
C++ Question

# error: passing ‘const Integer’ as ‘this’ argument of ‘Integer Integer::pow(int)’ discards qualifiers

I have

`Integer`
class that is supposed to simulate an integer mod n. Thus, it has constructors like:

``````Integer::Integer(int x)
: m(x), n(0)
{

}

Integer::Integer(int x, int y)
: n(y), m(x)
{
// if this->n greater than 1
if (this->n > 1)
{
// mod this->m by this->n
this->m %= this->n;
// if this->m is negative
if (this->m < 0)
{
this->m += this->n;
}
}
}
``````

There is also
`Integer::inverse()`
,
`Integer::pow(int)`
, which are needed for completeness of this question:

``````Integer Integer::inverse()
{
// Extended Euclidean Algorithm
int t = 0,
r = this->n,
newT = 1,
newR = this->m;
while (newR != 0)
{
int quotient = r / newR,
tCopy = t,
rCopy = r,
newTCopy = newT,
newRCopy = newR;
t = newT;
newT = tCopy - quotient * newTCopy;
r = newR;
newR = rCopy - quotient * newRCopy;
}
if (r > 1)
{
throw Integer(-1);
}
if (t < 0) t = t + this->n;
return Integer(t, this->n);
}

Integer Integer::squared()
{
return Integer(this->m * this->m, this->n);
}

Integer Integer::pow(int x)
{
// if x less than 0, return this->inverse().pow(-x)
if (x < 0)  return this->inverse().pow(-x);
// if x is 0, return Integer(1)
if (x == 0) return Integer(1, this->n);
// if x is 1, return *this
if (x == 1) return *this;
// if x is 2, return this->squared()
if (x == 2) return this->squared();
// if x greater than 2
if (x > 2)
{
// if x is even
if (x % 2 == 0)
{
// return this->pow(x/2).squared()
return this->pow(x/2).squared();
}
// return this->pow(x/2).squared() * (*this)
return this->pow(x/2).squared() * (*this);
}
}
``````

Problem I'm having is when I go to implement
`Integer::isQuadraticResidue() const`
:

``````bool Integer::isQuadraticResidue() const
{
// if this->n is zero
if (this->n == 0)
{
// this doesn't belong to Integers mod anything. check for perfect square instead
double baseSquareRoot = std::sqrt((double)this->m);
return (baseSquareRoot == (double)((int)baseSquareRoot));
}
// this is quadratic residue iff this->pow((this->n + 1) / 2) == Integer(1, this->n)
return (this->pow((n + 1) / 2).m == 1);
}
``````

I get following error:
`error: passing ‘const Integer’ as ‘this’ argument of ‘Integer Integer::pow(int)’ discards qualifiers`
. I think it has everything to do with the
`const`
on the end. What do?

EDIT: Class header file looks something like:

``````#ifndef INTEGER_H
#define INTEGER_H

#include <iostream>

class Integer
{
public:
Integer(int);
Integer(int, int);
// functions
Integer inverse();
Integer squared();
Integer pow(int);
Integer sqrt();
private:
int m, n;

};

#endif
``````

This is an issue with `const` correctness, where a `const` function is trying to call a non-`const` function.

``````// ...

Integer Integer::pow(int x);

// ....
``````

In this situation, `this` is an `Integer*` in `pow()`, and a `const Integer*` in `isQuadraticResidue()`; this means that `pow()` can call `isQuadraticResidue()`, because it's legal to add CV-qualifiers, but not the other way around (because `pow()` would have to accept `this` as a non-qualified `Integer*`, losing the `const` qualifier).

This is unallowed, because allowing it would mean that `isQuadraticResidue()` breaks its guarantee that it won't modify the instance, whether directly or indirectly. While it itself doesn't change state, it assumes that `pow()` does change state, because `pow()` isn't also `const` (and thus doesn't promise not to change state). Due to this, `isQuadraticResidue()` is unable to call `pow()`, because doing so would risk breaking its guarantee.

Considering that, there are two solutions for this issue.

1. Remove `const` from `isQuadraticResidue()`. This would naively solve the problem, but isn't recommended, because then you wouldn't be able to reap the benefits of `const` correctness.
2. Make all member functions that don't modify `Integer`'s logical state `const`, as well. This will require a bit more effort, but is overall safer. As they can then be called on a `const Integer` just as well as they can on an `Integer`, you will then be able to pass your instances around as `const` whenever they don't need to be modified, giving you a greater degree of safety.

``````Integer Integer::inverse() const;
Integer Integer::squared() const;
Integer Integer::pow()     const;
``````

This will need to be changed both in the functions' prototypes, and in their definitions.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download