Compiler says object is const, I can't see how - c++

I'm having trouble with this code:
NonCommutativePolynomial<SR> differential_at_wrt_variable
(std::map<VarId,SR> valuation, VarId variable) {
NonCommutativePolynomial<SR> result;
for(auto &monomial : monomials_) {
result += monomial.first.differential_at_wrt_variable(valuation, variable)
* monomial.second;
}
return result;
}
monomials_ has the type std::map<NonCommutativeMonomial<SR>,std::uint_fast16_t>.
In the line result += ... I'm getting this compiler error:
error: passing ‘const NonCommutativeMonomial’ as ‘this’
argument of ‘NonCommutativeMonomial
NonCommutativeMonomial::differential_at_wrt_variable(std::map&, VarId&) [with SR = LossySemiring]’ discards qualifiers
[-fpermissive]
Now I realize that this means that I am calling a method (function?) on a constant object where the method does not guarantee that it won't modify the object. What I don't understand is how monomial.first can be constant when I haven't declared it to be thus anywhere. Any ideas what I might be doing wrong?
EDIT:
See the answers below why monomial.first is constant. I need a non-constant copy of it, the class NonCommutativeMonomial<SR>has this copy constructor:
NonCommutativeMonomial(const NonCommutativeMonomial &m) = default;
However, when I call that using
NonCommutativeMonomial * mono = new NonCommutativeMonomial<SR>(monomial.first);
and work with mono afterwards, I still get the same error.

In std::map keys are constant objects and you must never change them.
EDIT:
I'd suggest the following change:
NonCommutativePolynomial<SR> result;
for(auto &monomial : monomials_) {
NonCommutativePolynomial<SR> tmp(monomial.first);
result += tmp.differential_at_wrt_variable(valuation, variable)
* monomial.second;
}

it seems that member function differential_at_wrt_variable has no qualifier const while monomial.first is a const object.
Value type is defined for std::map as
typedef pair<const Key, T> value_type;
that is Key has qualifier const.

The value_type of a std::map<KeyType, MappedType> is declared as a std::pair<const KeyType, MappedType>.
An iterator for a std::map (which is what your for loop is using) is over the map's value_type.
In your case this results in monomial.first having the type const NonCommutativeMonomial<SR> which, as you recognise, cannot be used with a non-const member function.
The reason for the key in the value type being const is to prevent the map keys themselves being modified during the iteration.

Related

Move std::array to an other std::array

I'm trying to move an array to an other array (for initialize my datas structure).
My code:
void MonitorModule::setParameters(const std::array<std::string, IMonitorModule::MAX_CONTENT> &parameters) const {
this->_parameters = parameters;
}
// Inside the structure "MonitorModule" as private
std::array<std::string, IMonitorModule::MAX_CONTENT> _parameters;
This is returning the following error:
error: no viable overloaded '='
How can I do this move of two std::array ?
Thanks.
setParameters() is qualified as const, which means it can only be called on a const MonitorModule object and thus its _parameters member cannot be modified. That is why the compiler cannot find a suitable operator= to assign another array to _parameters.
You need to drop the const qualifier from the declaration of setParameters().
The keyword const after method definition prevents modifying its members, so you should remove it or make _parameters mutable.
MonitorModule::setParameters is qualified const, meaning that it can't change object members.
Simply remove the const qualification.

vector<bool> raises an error on const data() method

I have the following code:
#include <vector>
struct TestStruct {
std::vector<float> float_vect;
std::vector<bool> bool_vect;
};
void func(const TestStruct & test)
{
const float * p1 = test.float_vect.data(); //<--- this line works fine
const bool * p2 = test.bool_vect.data(); //<--- on this line error happens
}
int main()
{
TestStruct test;
func(test);
}
Error message:
passing 'const std::vector' as 'this' argument of 'void std::vector::data() [with _Alloc = std::allocator]' discards qualifiers [-fpermissive]
data() method of std::vector have const specified.
Why this method works fine on float vector, and raises an error on boolean vector ?
vector<bool> is a specialization of a good old vector<T> and it may be implemented differently from ordinary vector (e.g. some space-saving optimizations may be employed). Side-effect of such design is that it does not always behave as ordinary vector (many consider vector<bool> to be broken because of that).
For example, the reference at http://en.cppreference.com/w/cpp/container/vector_bool does not mention vector<bool>::data() at all. Therefore - you should not use it when using vector with type bool. The fact that you don't get an error similar to method not found is - in your case - just a matter of how vector<bool> is implemented by your compiler.
std::vector<bool> is a template specialization of the class std::vector<T> in the STL. In order to use less memory, the boolean values are stored by 8 in a byte. It means there is no direct data accessible as you expect because the class doesn't store it in the same way than for other types.
Look at the doc :
The specialization has the same member functions as the unspecialized vector, except data, emplace, and emplace_back, that are not present in this specialization.

Difference between const and non-const method?

int CRegister::CountCars(const string& name, const string& surname)const{
const pair<string,string> wholename(name,surname);
vector<CDriver>::iterator Diterator=lower_bound(m_Drivers.begin(),m_Drivers.end(),wholename);
if (Diterator<m_Drivers.end()){
if(Diterator->m_name.compare(wholename.first)!=0 || Diterator->m_surname.compare(wholename.second)!=0) return 0;
return Diterator->m_DriversNumber;
}
return 0;
}
Hello, when I try to compile this, it throws error on the third line:
"conversion from ‘__gnu_cxx::__normal_iterator<const CDriver*, std::vector<CDriver> >’ to non-scalar type ‘std::vector<CDriver>::iterator {aka __gnu_cxx::__normal_iterator<CDriver*, std::vector<CDriver> >}’ requested
When I set the function CountCars as a non-const, it compiles without problems. What should I change to fix this? (the function has to be const)
To solve your problem you have to use a const_iterator
The reason is the following : The method is marked const, which means that the method itself is not going to change state of the object instance upon which the method is invoked.
Therefore within a const method you cannot call any other method on the same object that is not marked const. Because of course that new call does not garantee that it is const so can the first method not claim to be const anymore.
by declaring the iterator const you are going to use the const version of lower_bound.
Try using a const_iterator:
vector<CDriver>::const_iterator Diterator
// ^^^^^^
Consider using a const_iterator, e.g.
vector<CDriver>::const_iterator Diterator
= lower_bound(m_Drivers.begin(), m_Drivers.end(), wholename);
If you can compile in C++11/14, using auto helps as well:
auto Diterator = lower_bound(m_Drivers.begin(), m_Drivers.end(), wholename);
(With auto, the compiler deduces the correct iterator type, without requiring you to correctly "spell" it explicitly in code.)

const function and references

If you notice in the following functions they both have the same for loop that searches for a integer location. Pop() compiles but I get an error for top() having to do with the const qualifiers. The heap class inherits from eecs281heap which stores a functor Comp compare where Comp is the typename. The instructor told us the only way to access the functor is through this->() so i'm just lookin for some guidance here. Thanks
error: passing ‘const larger’ as ‘this’ argument of ‘bool larger::operator()(int, int)’ discards qualifiers
This happens after running the following in int main. Through testing I already know the constructor works properly.
vector <int> data={10,2,13};
poorman_heap<int,larger> y(data.begin(),data.end());
template<typename TYPE, typename COMP>
void poorman_heap<TYPE, COMP>::pop() {
int location=0;
for(int i=1;i<data.size();i++){
if(this->compare(data.at(i),data.at(location))){
location=i;
}
}
data.erase(data.begin()+location);
return;
}
template<typename TYPE, typename COMP>
const TYPE& poorman_heap<TYPE, COMP>::top() const {
int location=0;
for(int i=1;i<data.size();i++){
if(this->compare(data.at(i),data.at(location))){
location=i;
}
}
return data.at(location);
}
P.S. greater is
struct greater{
bool operator()(int x,int y){
return x>y;
}
}
Make the call operator of greater a const operator:
struct greater
{
bool operator()(int x,int y) const
{
return x>y;
}
}
The same applies to whatever this->compare resolves to. It needs to be const.
It doesn't make much sense for a comparator to be non-const.
It looks like the problem is that the compare member has operator() declared as a non-const function. Since it sounds like you don't have the ability to change that, you might be able to get the behavior that you want by declaring it as a mutable member in poorman_heap.
The mutable keyword lets you distinguish between an object being "physically const" (meaning the actual bytes don't change and being "logically const" (meaning the bytes might change but the value of the object isn't different in a fundamental sense). Basically it means that something "doesn't count" for the purposes of const-ness. The classic example in my mind is lazy initialization - you want to declare the get_value() function on a class const, but you also don't want to waste time computing the value if no one uses it, so you declare the value mutable and now you're allowed to calculate it and assign to it inside get_value() even though it is a const member function.

Wrong function prototype used by compiler?

I faced a compilation problem that I do not understand, I have simplified it a bit for explanation below.
Basically, it involves having 2 different getters (a const and non-const one) that return a container (a map in this example) with const, respectively non-const value_type.
What puzzles me is that in the example below, the compiler seems unable to use the const getter on a non-const object:
#include "stdafx.h"
#include <utility>
#include <map>
class TestObject
{
public:
TestObject() {}
virtual ~TestObject() {}
};
typedef std::pair<const TestObject*, const TestObject*> ConstTestObjectPair;
typedef std::pair<TestObject*, TestObject*> TestObjectPair;
class Test
{
TestObject* m_pObject;
public:
Test() {m_pObject = new TestObject();}
virtual ~Test() {delete m_pObject;}
std::map<unsigned, ConstTestObjectPair> GetObject() const
{
std::map<unsigned, ConstTestObjectPair> map;
map.insert(std::make_pair(0, std::make_pair(m_pObject, m_pObject)));
return map;
}
std::map<unsigned, TestObjectPair> GetObject()
{
std::map<unsigned, TestObjectPair> map;
map.insert(std::make_pair(0, std::make_pair(m_pObject, m_pObject)));
return map;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Test* pTest = new Test();
const Test* pConstTest = pTest;
std::map<unsigned, ConstTestObjectPair> CTO = pTest->GetObject(); // Not compiling, I don't get why!!!
CTO = pConstTest->GetObject();
std::map<unsigned, TestObjectPair> TO = pTest->GetObject();
//TO = pConstTest->GetObject(); // Not working, this is expected
return 0;
}
I tried with both VS2010 and gcc and neither accepts to compile this code. Here is the compilation error returned by VS2010:
1>c:\test.cpp(48): error C2440: 'initializing' : cannot convert from 'std::map<_Kty,_Ty>' to 'std::map<_Kty,_Ty>'
1> with
1> [
1> _Kty=unsigned int,
1> _Ty=TestObjectPair
1> ]
1> and
1> [
1> _Kty=unsigned int,
1> _Ty=ConstTestObjectPair
1> ]
1> No constructor could take the source type, or constructor overload resolution was ambiguous
Could someone explain me why the compiler cannot find/use the correct prototype on the non-const object?
Thanks a lot!
If you're really curious, check out section 13.3.3 of the C++03 standard, which describes how the "best viable function" is determined. Here are some important points:
The selection criteria for the best function are the number of arguments, how well the arguments
match the types of the parameters of the candidate function, how well (for nonstatic member functions) the
object matches the implied object parameter, and certain other properties of the candidate function. [Note:
the function selected by overload resolution is not guaranteed to be appropriate for the context. Other
restrictions, such as the accessibility of the function, can make its use in the calling context ill-formed. ]
And later:
If there is exactly one viable function that is a better function than all other viable functions, then it is the
one selected by overload resolution
Note that the return type of the function is not mentioned in this criteria. So the non-const method is selected as most valid, because its "implied object parameter" (essentially the "this" pointer) is non-const. This all happens before the conflict with the return type is detected.
To solve this problem, I would either:
Change your design so that ConstTestObjectPair isn't needed, and you can just use const TestObjectPair (preferred solution)
Cast your non-const objects to const ones when needed
What puzzles me is that in the example below, the compiler seems unable to use the const getter on a non-const object
It is not "unable" but required to chose the other one.
Overloading is selected using the passed actual parameters. For member function including the hidden param used for this. For T* the non-const overload is selected, if you want the other you must use a const T* by cast or other means.
Actually it is a common mistake to think the return type will be used some way and the function that returns what you want to use in the expression gets selected. It is just not so.
The problem is quite simple. pTest is a pointer to an object of type Test, which is not const. Hence in the call pTest->GetObject() the non-const member function is selected, that is
std::map<unsigned, TestObjectPair> GetObject()
As you see, this function returns a value of type std::map<unsigned, TestObjectPair>. But then you try to initialize the variable CTO of type
std::map<unsigned, ConstTestObjectPair>
with this value. To do that, the compiler needs to convert the returned value to this type. But there is no conversion constructor to do that. And that is what the compiler error tells you.
C++ compiler will choose the explicit overrided method, so here pTest is a non-const viable and pConstTest is const one.
Test* pTest = new Test();
const Test* pConstTest = pTest;
pTest->GetObject will choose the non-const GetObject:
std::map<unsigned, TestObjectPair> GetObject()
{
std::map<unsigned, TestObjectPair> map;
map.insert(std::make_pair(0, std::make_pair(m_pObject, m_pObject)));
return map;
}
pConstTest->GetObject() will choose the const GetObject:
std::map<unsigned, ConstTestObjectPair> GetObject() const
{
std::map<unsigned, ConstTestObjectPair> map;
map.insert(std::make_pair(0, std::make_pair(m_pObject, m_pObject)));
return map;
}
the first error happened when you assign a returned
std::map<unsigned, TestObjectPair> value
to a
std::map<unsigned, ConstTestObjectPair> viable