Pointer to a const member variable - c++

I was wondering what the syntax was for a pointer to a constant member variable.
I know a pointer to a non-const member function and a pointer to a const member function are expressly different types, ie, the following are two distinct types:
typedef void (Foo::*Bar)(void);
typedef void (Foo::*ConstBar)(void) const;
I was wondering if the same could be said of pointers to non-const and const member variables, ie are the following two distinct types as well, and if so, what is the syntax of the latter:
typedef int (Foo::*var);
typedef int (Foo::*constVar) const; // Not the correct syntax.
Thanks.

The type of the pointer-to-member needs to match the type of the member:
typedef int (Foo::*var); // pointer to a data member of type 'int'
typedef const int (Foo::*cvar); // pointer to a data member of type 'const int'
The const-qualification of a member function is a part of its type, just like the return type is a part of its type.

Just to make it funnier:
typedef const int (Foo::*(Foo::*ConstBar)(void) const);
ConstBar is a pointer to a const-member function taking no arguments and returning a pointer to a const-member of type int.
A general tip of how to remember the syntax in your question: you just write it the way you would define the member of the class
void name(void) const; // const function
const int name; // const member
And then replace name by (Foo::*name), resulting in:
void (Foo::*name)(void) const; // pointer to const function
const int (Foo::*name); // pointer to const member

Related

mutable with const pointer in C++

If I use mutable with const pointer like this:
class Test
{
public:
mutable const int* ptr; // OK
};
It's working fine.
But, If I use like this :
class Test
{
public:
mutable int * const ptr; // Error
};
An error :
prog.cpp:6:25: error: const 'ptr' cannot be declared 'mutable'
mutable int * const ptr;
^
prog.cpp: In function 'int main()':
prog.cpp:11:7: error: use of deleted function 'Test::Test()'
Test t;
^
prog.cpp:3:7: note: 'Test::Test()' is implicitly deleted because the default definition would be ill-formed:
class Test
^
prog.cpp:3:7: error: uninitialized const member in 'class Test'
prog.cpp:6:25: note: 'int* const Test::ptr' should be initialized
mutable int * const ptr;
Why does compiler give an error in second case?
const int * ptr;
The first is a pointer to constant data, which means you can change the pointer and where it points to, but you can't change the data it points to.
int * const ptr;
The second is a constant-pointer to non-constant data, which means you must initialize the pointer in your constructor(s) and then you can't make it point anywhere else. The data it points to can be modified though.
The mutable part in both cases applies to the pointer, the actual member variable, not the data it points to. And since the variable can't be both mutable and constant at the same time you should get an error message for that.
The 2nd case causes error because mutable and const can't be mixed; mutable can only be used with non-const data member.
applies to non-static class members of non-reference non-const type and specifies that the member does not affect the externally visible state of the class (as often used for mutexes, memo caches, lazy evaluation, and access instrumentation). mutable members of const class instances are modifiable.
BTW the following code causes the same error.
class Test
{
public:
mutable const int x; // Error;
mutable int const x; // ditto;
};
The 1st case is fine, because const int* is not a const pointer, but a pointer to const. That means it's fine to modify the pointer itself, and you can mark it mutable. (But you can't modify the pointee.)
BTW const pointer to const (e.g. mutable const int* const ptr;) causes the same error too.
struct Test
{
const int* ptr;
};
Translation: "The structure has a member. The member is a pointer. The pointer points to an integer which may not be mutated via the pointer."
The pointer itself may be mutated though, to point to a different const int.
It's probably simpler if we pick a non-reference type, so you can separate the types of the member (in your example a pointer), from the type of the pointed-to object.
struct Test1
{
int value;
};
Now, adding the mutable keyword to get
struct Test2
{
mutable int value;
};
just means we're allowed to mutate the member even when the structure itself is otherwise const.
In other words, all of this is OK in both cases:
Test1 a { 123 };
Test2 b { 123 };
// now mutate the object through a non-const reference
a.value = 42;
b.value = 42;
but this is different:
const Test1& ca = a;
ca.value = 69; // NO, a member of a const object is const
const Test2& cb = b;
cb.value = 69; // OK, a mutable member of a const object
So, now that we understand how mutable is being applied, the consider the problematic line:
mutable int * const ptr;
This is saying that ptr is both mutable (able to be mutated even when the object it's a member of is otherwise const) and const (not able to be mutated even when the object it's a member of is otherwise non-const).
The two are obviously contradictory.
The bugs.eclipse.org say's:
The mutable specifier can be applied only to names of class data
members (9.2) and cannot be applied to names declared const or
static, and cannot be applied to reference members.

Why pointer to non-const member function can't point const member function and opposite?

What is the reason why pointers to member functions, can't point to const member functions?
struct A {
void g() {};
void f() const {}
};
Later in code:
void (A::* fun)() = &A::f;
This code produces:
error: cannot convert ‘void (A::*)()const’ to ‘void (A::*)()’ in initialization
Of course it compiles with &A::g instead of &A::f.
In opposite situation:
void (A::* fun)() const = &A::g;
The error is:
error: cannot convert ‘void (A::*)()’ to ‘void (A::*)()const’ in initialization
The second case is rather clear. const pointer isn't expected to modify the object so it can't hold the function which does it. But why it's not possible to assign const member function to non-const member function as in the first case?
It looks like the rule for normal pointers where casting const to non-const would allow to modify the value, but I don't see the point here, where const-correctness is checked in function definition, before such assignment.
What is the reason why pointers to member functions, can't point to const member functions?
Because the const modifier is part of the function signature. Once you declare a function pointer, that function pointer can only be used to assign pointers to function that have the same function signature.
Non-static member functions have an extra hidden this parameter. Given the existence of that that extra hidden parameter, a non-static void A::f() const; behaves much like void A__f(const A *__this), and the behaviour you see for member functions models the behaviour for non-member functions.
void f(void *);
void (*pf)(const void *) = f; // also an error
As for whether it could break on any implementation, I suppose in theory, an implementation is permitted to read a void * parameter from a different register than a const void * parameter, and if so, the result of the conversion (were it valid) could not be used to call f properly. I have no idea why any implementor would make such a decision, and I don't know of any real implementation that does so, but it's one allowed by the standard.

Why is an array argument treated as a const array?

I am working with a member function that just sets the object's internal orientation to the values given in the argument:
void A::SetOrientation(float a[3]);
In another class, I have the following:
class B
{
public:
RestoreStateTo(A* const o_pA) const
private:
float d_orientation[3];
};
void
B::RestoreStateTo(A* const o_pA) const
{
o_pA->SetOrientation(d_orientation);
}
I get the following compiler error (with Visual Studio 2010):
error C2664: 'void A::SetOrientation(float [])' : cannot convert parameter 1 from 'const float [3]' to 'float []'
I found that I can avoid the issue with o_pA->SetOrientation(const_cast<float *>(d_orientation));, but I'd like to get a better grasp of what is going on.
I would appreciate an explanation as to why the array argument is converted to a const array as well as suggest the right approach to dealing with the error?
Because the prototype of your function void B::RestoreStateTo(A* const o_pA) const says you will not modify any member of B.
Since d_orientation is an attribute of B, it is const in this function.
Your SetOrientation function should take in a const,
void A::SetOrientation(const float a[3]);
Otherwise, it's possible that A::SetOrientation will modify the array you pass in. Because you have "B::RestoreStateTo(A* const o_pA) const", it means that the compiler won't let you pass a pointer to B::d_orientation as a non-const input, because A::SetOrientation has no guarantee not to modify it.
You have declared a const member function, and therefore all the members of this will be treated as const inside that function. So it shouldn't be surprising that d_orientation is treated as const.
It's the same principle that makes this code illegal:
const B* p = ...;
p->d_orientation[0] = 0.0f; // error, assigning member of `const` object

c++ constant function declaration variants?

Are all of the below declarations the same? If so, what is the standard way to declare a constant function?
const SparseMatrix transpose();
SparseMatrix transpose() const;
const SparseMatrix transpose() const;
The const on the left of the function name means the object that is returned cannot be modified. The const on the right means the method is apart of a class and does not modify any of its data members. Unless or course any of its data members are declared with the mutable keyword, in which case modification thereof is permitted despite a const guard.
The placement of the const keyword is unimportant when the return type of the function is of non-pointer type:
T const f(); // same as const T f();
However, note that the placement of the const keyword matters when using a pointer as the return type. For example:
const T* f();
This method returns a pointer to a const T. That is, what it points to is immutable. So you cannot do an assignment through a dereference of the returned pointer:
T* x = f();
*x = y; // error: assignment of read-only location '*(const T*)x'
When const is placed on the immediate right of the return type (that is a pointer), it means the pointer is const and cannot be changed.
T* const f();
int main()
{
T* x const;
x = f(); // error: assignment of read-only variable 'x'
}
Furthermore, if we have const on both sides of a pointer return type, and have const denoting "no modification of class members", then it's read as the following:
const T* const f() const;
A const member function named f that returns a const pointer to a const T
The first one will return a SparseMatrix that is const and cant be changed.
The second one declares a function that returns a SparseMatrix and assures the function will not change any class variables (assuming it is a member function, otherwise it wouldnt make sense with this deceleration) except for mutable members.
The final one does both.
1) return a const value
2) const function, no member changes inside it
3) 1)+2)

pointer assignment

I have the following template structure:
template <typename scalar_type>
struct postc_params{
scalar_type delta;
unsigned int time_horizon;
matrix_math::matrix<scalar_type> dynamics;
boost::shared_ptr<continuous_set> invariant_set_ptr;
boost::shared_ptr<continuous_set> input_set_ptr;
boost::shared_ptr<continuous_set> initial_set_ptr;
};
Now, I have a templated class with a private member of the above structure type
template <typename scalar_type>
class A{
....
private:
....
postc_params<scalar_type> my_postc;
};
Inside a member function definition of class A, I have the following line of code:
my_postc.initial_set_ptr = my_postc.initial_set_ptr->transform(some_obj);
transform function returns a pointer of type
boost::shared_ptr<continuous_set>
With this code, I have the following error:
passing 'const boost::shared_ptr' as 'this' argument of 'boost::shared_ptr< >& boost::shared_ptr< >::operator=
(const boost::shared_ptr&) [with Y = const continuous::continuous_set, T = continuous::continuous_set]' discards qualifiers
Can anyone help me out with the cause?
Is the member function in A const?
If I am reading your code right, you are trying to change a member of a class from a const member function which is not allowed. Either remove the const from the member function or make the member mutable.
So,
mutable postc_params<scalar_type> my_postc;
However, I would take care with this method. Maybe reevaluate why the method that is changing my_postc is const. Either it should not be const or it should not be changing my_postc.
you are trying to assign to a const pointer as per the error message: "passing 'const boost::shared_ptr' as 'this' argument"
the member function you mention is surely const hence the error
you should rather reconsider your design than throw mutable here and there in your code.