How to work around 'const' definition in library - c++

I'm using a library that defines some data type classes usually implemented as tight wrappers around a std::vector<>. The type hierarchy is several layers deep, mostly only adding elaborated constructors.
My problem: the base class defines its std::vector as private (which is fine), but only adds an accessor method as const. The derived class doesn't even have access to it. The library looks like this (shorted for clarity):
template <class T> class BaseList
{
public:
BaseList (const T data0) : data_ (1) {
data_[0] = data0; }
const T & operator[] (const size_t nr) const {
// does out off bounds check here
return data_[nr]; }
private:
std::vector<T> data_;
}
class FancyClass : public BaseList<SomeEnumType>
{
public:
FancyClass (const SomeOtherEnumType data0)
: BaseList<SomeEnumType> ( static_cast<SomeEnumType> (data))
{}
}
Now as I see it, the const definition is completely bogus. No internal method relies on the vector really being constant, neither do I in my external code.
What I like to do is simply this:
strukt MyType {
FancyClass myData;
bool otherData;
}
int main() {
MyType storage = {FancyClass(0), false};
storage.myData[0] = 5;
}
Which of course doesn't work because of the const-ness. ("assignment of read-only location")
With the responsibility completely on my side: is there some const_cast magic I could do to make this structure writable?
The only other possibility I know would be to completely replicate the type hierarchy in my code, but this would still leave me with either a lot of casts or a toFancyClass() function to call whenever I interface library code.
Any Ideas? Thanks!
(Please don't comment on the code quality of the library. If I could change that, I wouldn't be asking this question ...)

Now as I see it, the const definition is completely bogus. No internal method relies on the vector really being constant, neither do I in my external code.
The const qualifier on a method doesn't mean it relies on the vector being constant. It means that the method will not modify the state of the object. It is added so that the following code will compile.
void f(const FancyClass a)
{
cout<<a[0];
}
The above code will not above compile without the const qualifiers on the [] method.
Anyway, the following should work
SomeEnumType & r = const_cast<SomeEnumType &>(storage.myData[0]);
r = b;
where b is an enum of type SomeEnumType
However if your storage object is actually a const object, then it will lead to undefined behaviour.

The simplest would be to add non-const version of the operator[]. Otherwise, you might cause an UB by casting away the constness with using const_cast.
You can throw away the constness like this :
int main() {
MyType storage = {FancyClass(0), false};
const_cast< SomeEnumType& >( storage.myData[0] ) = 5;
}

Normally operator[] comes in pairs of a mutable and a const version.. (See: Operator overloading)
Of course there is a const_cast-based solution, but it involves undefined behaviour (you're not allowed to change a value after casting away constness!)

Related

lvalue and rvalue getter, is it possible to remove them?

Let's say we have this simple class
struct MyClass {
const std::string &getString() const & {
return m_string;
}
std::string getString() && {
return std::move(m_string);
}
private:
std::string m_string;
};
As we can see, the m_string acts as a non mutable variable in the sense that we cannot modify it.
This structure also preserve the fact that if we move one instance of MyClass to another, the m_string attribute will be moved as well.
Now, we are going to try to refactor the prior structure :
struct MyClass {
std::string m_string;
};
Here, we keeps the fact that we can access it or move it, but we lose the "immutability"... So I tried to write it like that :
struct MyClass {
const std::string m_string;
};
Here we get the immutability thing, however, we lose the potential optimization when we move the object...
So, is it possible to have a behavior similar to the first code, without writing all the getter?
EDIT: the std::string is just for example, but the idea must be usable with all kind of objects
So, is it possible to have a behavior similar to the first code, without writing all the getter?
I can't think of any.
Having said that, the overhead of writing getters and setters for member variables is not such a big burden that I would spend too much time thinking about it.
However, there are some who think that getters and setters of member variables don't add enough protection to a class to even worry about them. If you subscribe to that line of thinking, you can get rid of the getters and setters altogether.
I have used the "no getters and setters" principle for containers of data enough times that I find it natural in many use cases.
You can implement this behavior using a template wrapper type. It seems you want a type that works well with copy and move construction and assignment, but which only provides const access to the wrapped object. All you should need is a wrapper with a forwarding constructor, an implicit conversion operator and dereferencing operators (to force the conversion when implicit conversion doesn't work) :
template<class T>
class immutable
{
public:
template<class ... A>
immutable(A&&... args) : member(std::forward<A>(args)...) {}
public:
operator const T &() const { return member; }
const T & operator*() const { return member; }
const T * operator->() const { return &member; }
private:
T member;
};
This will work well with compiler generated copy and move construction and assignment. The solution is not 100% transparent however. The wrapper will implicitly convert to a reference to the wrapped type, if the context allows it :
#include <string>
struct foo
{
immutable<std::string> s;
};
void test(const std::string &) {}
int main()
{
foo f;
test(f.s); // Converts implicitly
}
But it will need an extra dereference to force the conversion in contexts where implicit conversion will not work :
int main()
{
foo f;
// std::cout << f.s; // Doesn't work
std::cout << *(f.s); // Dereference instead
// f.s.size(); // Doesn't work
f.s->size(); // Dereference instead
}
There was a proposal to add overloading of the . operator, which would allow most cases to work as intended, without a dereferencing. But I'm not sure what the current state of the proposal is.
The solution is to use std::shared_ptr<const std::string>. A shared pointer to a immutable object has value semantic. Copy-on-write can be achieved using shared_ptr::unique(). See Sean Parent presentation 47:46 https://youtu.be/QGcVXgEVMJg.
If only you are willing to declare the copy and defuslt ctor as =default and define the move ctor with const_cast cheat.
MyClass::Myclass()=default;
MyClass::Myclass(Myclass const&)=default;
MyClass::Myclass(Myclass && m)
: m_string{std::move(const_cast<std::string&>(m.m_string))}{};

Accessing methods returning copy and reference values respectively [duplicate]

I'm working on learning C++ with Stroustrup's (Programming Principles & Practice Using C++) book. In an exercise we define a simple struct:
template<typename T>
struct S {
explicit S(T v):val{v} { };
T& get();
const T& get() const;
void set(T v);
void read_val(T& v);
T& operator=(const T& t); // deep copy assignment
private:
T val;
};
We're then asked to define a const and a non-const member function to get val.
I was wondering: Is there any case where it makes sense to have non-const get function that returns val?
It seems much cleaner to me that we can't change the value in such situations indirectly. What might be use cases where you need a const and a non-const get function to return a member variable?
Non-const getters?
Getters and setters are merely convention. Instead of providing a getter and a setter, a sometimes used idiom is to provide something along the line of
struct foo {
int val() const { return val_; }
int& val() { return val_; }
private:
int val_;
};
Such that, depending on the constness of the instance you get a reference or a copy:
void bar(const foo& a, foo& b) {
auto x = a.val(); // calls the const method returning an int
b.val() = x; // calls the non-const method returning an int&
};
Whether this is good style in general is a matter of opinion. There are cases where it causes confusion and other cases where this behaviour is just what you would expect (see below).
In any case, it is more important to design the interface of a class according to what the class is supposed to do and how you want to use it rather than blindly following conventions about setters and getters (eg you should give the method a meaningful name that expresses what it does, not just in terms of "pretend to be encapsulated and now provide me access to all your internals via getters", which is what using getters everywhere actually means).
Concrete example
Consider that element access in containers is usually implemented like this. As a toy example:
struct my_array {
int operator[](unsigned i) const { return data[i]; }
int& operator[](unsigned i) { return data[i]; }
private:
int data[10];
};
It is not the containers job to hide the elements from the user (even data could be public). You dont want different methods to access elements depending on whether you want to read or write the element, hence providing a const and a non-const overload makes perfectly sense in this case.
non-const reference from get vs encapsulation
Maybe not that obvious, but it is a bit controversial whether providing getters and setters supports encapsulation or the opposite. While in general this matter is to a large extend opinion based, for getters that return non const references it is not so much about opinions. They do break encapuslation. Consider
struct broken {
void set(int x) {
counter++;
val = x;
}
int& get() { return x; }
int get() const { return x; }
private:
int counter = 0;
int value = 0;
};
This class is broken as the name suggests. Clients can simply grab a reference and the class has no chance to count the number of times the value is modified (as the set suggests). Once you return a non-const reference then regarding encapsulation there is little difference to making the member public. Hence, this is used only for cases where such behaviour is natural (eg container).
PS
Note that your example returns a const T& rather than a value. This is reasonable for template code, where you dont know how expensive a copy is, while for an int you wont gain much by returning a const int& instead of an int. For the sake of clarity I used non-template examples, though for templated code you would probably rather return a const T&.
First let me rephrase your question:
Why have a non-const getter for a member, rather than just making the member public?
Several possible reasons reasons:
1. Easy to instrument
Whoever said the non-const getter needs to be just:
T& get() { return val; }
? it could well be something like:
T& get() {
if (check_for_something_bad()) {
throw std::runtime_error{
"Attempt to mutate val when bad things have happened");
}
return val;
}
However, as #BenVoigt suggests, it is more appropriate to wait until the caller actually tries to mutate the value through the reference before spewing an error.
2. Cultural convention / "the boss said so"
Some organizations enforce coding standards. These coding standards are sometimes authored by people who are possibly overly-defensive. So, you might see something like:
Unless your class is a "plain old data" type, no data members may be public. You may use getter methods for such non-public members as necessary.
and then, even if it makes sense for a specific class to just allow non-const access, it won't happen.
3. Maybe val just isn't there?
You've given an example in which val actually exists in an instance of the class. But actually - it doesn't have to! The get() method could return some sort of a proxy object, which, upon assignment, mutation etc. performs some computation (e.g. storing or retrieving data in a database; or flipping a bit, which itself is not addressable like an object needs to be).
4. Allows changing class internals later without changing user code
Now, reading items 1. or 3, above, you might ask "but my struct S does have val!" or "by my get() doesn't do anything interesting!" - well, true, they don't; but you might want to change this behavior in the future. Without a get(), all of your class' users will need to change their code. With a get(), you only need to make changes to the implementation of struct S.
Now, I don't advocate for this kind of a design approach approach, but some programmers do.
get() is callable by non const objects which are allowed to mutate, you can do:
S r(0);
r.get() = 1;
but if you make r const as const S r(0), the line r.get() = 1 no longer compile, not even to retrieve the value, that's why you need a const version const T& get() const to at least to able to retrieve the value for const objects, doing so allows you do:
const S r(0)
int val = r.get()
The const version of member functions try to be consistent with the constness property of the object the call is made on, i.e if the object is immutable by being const and the member function returns a reference, it may reflect the constness of the caller by returning a const reference, thus preserving the immutability property of the object.
It depends on the purpose of S. If it's some kind of a thin wrapper, it might be appropriate to allow the user to access the underlaying value directly.
One of the real-life examples is std::reference_wrapper.
No. If a getter simply returns a non-const reference to a member, like this:
private:
Object m_member;
public:
Object &getMember() {
return m_member;
}
Then m_member should be public instead, and the accessor is not needed. There is absolutely no point making this member private, and then create an accessor, which gives all access to it.
If you call getMember(), you can store the resulting reference to a pointer/reference, and afterwards, you can do whatever you want with m_member, the enclosing class will know nothing about it. It's the same, as if m_member had been public.
Note, that if getMember() does some additional task (for example, it doesn't just simply return m_member, but lazily constructs it), then getMember() could be useful:
Object &getMember() {
if (!m_member) m_member = new Object;
return *m_member;
}

Reasons for defining non-const 'get' member functions?

I'm working on learning C++ with Stroustrup's (Programming Principles & Practice Using C++) book. In an exercise we define a simple struct:
template<typename T>
struct S {
explicit S(T v):val{v} { };
T& get();
const T& get() const;
void set(T v);
void read_val(T& v);
T& operator=(const T& t); // deep copy assignment
private:
T val;
};
We're then asked to define a const and a non-const member function to get val.
I was wondering: Is there any case where it makes sense to have non-const get function that returns val?
It seems much cleaner to me that we can't change the value in such situations indirectly. What might be use cases where you need a const and a non-const get function to return a member variable?
Non-const getters?
Getters and setters are merely convention. Instead of providing a getter and a setter, a sometimes used idiom is to provide something along the line of
struct foo {
int val() const { return val_; }
int& val() { return val_; }
private:
int val_;
};
Such that, depending on the constness of the instance you get a reference or a copy:
void bar(const foo& a, foo& b) {
auto x = a.val(); // calls the const method returning an int
b.val() = x; // calls the non-const method returning an int&
};
Whether this is good style in general is a matter of opinion. There are cases where it causes confusion and other cases where this behaviour is just what you would expect (see below).
In any case, it is more important to design the interface of a class according to what the class is supposed to do and how you want to use it rather than blindly following conventions about setters and getters (eg you should give the method a meaningful name that expresses what it does, not just in terms of "pretend to be encapsulated and now provide me access to all your internals via getters", which is what using getters everywhere actually means).
Concrete example
Consider that element access in containers is usually implemented like this. As a toy example:
struct my_array {
int operator[](unsigned i) const { return data[i]; }
int& operator[](unsigned i) { return data[i]; }
private:
int data[10];
};
It is not the containers job to hide the elements from the user (even data could be public). You dont want different methods to access elements depending on whether you want to read or write the element, hence providing a const and a non-const overload makes perfectly sense in this case.
non-const reference from get vs encapsulation
Maybe not that obvious, but it is a bit controversial whether providing getters and setters supports encapsulation or the opposite. While in general this matter is to a large extend opinion based, for getters that return non const references it is not so much about opinions. They do break encapuslation. Consider
struct broken {
void set(int x) {
counter++;
val = x;
}
int& get() { return x; }
int get() const { return x; }
private:
int counter = 0;
int value = 0;
};
This class is broken as the name suggests. Clients can simply grab a reference and the class has no chance to count the number of times the value is modified (as the set suggests). Once you return a non-const reference then regarding encapsulation there is little difference to making the member public. Hence, this is used only for cases where such behaviour is natural (eg container).
PS
Note that your example returns a const T& rather than a value. This is reasonable for template code, where you dont know how expensive a copy is, while for an int you wont gain much by returning a const int& instead of an int. For the sake of clarity I used non-template examples, though for templated code you would probably rather return a const T&.
First let me rephrase your question:
Why have a non-const getter for a member, rather than just making the member public?
Several possible reasons reasons:
1. Easy to instrument
Whoever said the non-const getter needs to be just:
T& get() { return val; }
? it could well be something like:
T& get() {
if (check_for_something_bad()) {
throw std::runtime_error{
"Attempt to mutate val when bad things have happened");
}
return val;
}
However, as #BenVoigt suggests, it is more appropriate to wait until the caller actually tries to mutate the value through the reference before spewing an error.
2. Cultural convention / "the boss said so"
Some organizations enforce coding standards. These coding standards are sometimes authored by people who are possibly overly-defensive. So, you might see something like:
Unless your class is a "plain old data" type, no data members may be public. You may use getter methods for such non-public members as necessary.
and then, even if it makes sense for a specific class to just allow non-const access, it won't happen.
3. Maybe val just isn't there?
You've given an example in which val actually exists in an instance of the class. But actually - it doesn't have to! The get() method could return some sort of a proxy object, which, upon assignment, mutation etc. performs some computation (e.g. storing or retrieving data in a database; or flipping a bit, which itself is not addressable like an object needs to be).
4. Allows changing class internals later without changing user code
Now, reading items 1. or 3, above, you might ask "but my struct S does have val!" or "by my get() doesn't do anything interesting!" - well, true, they don't; but you might want to change this behavior in the future. Without a get(), all of your class' users will need to change their code. With a get(), you only need to make changes to the implementation of struct S.
Now, I don't advocate for this kind of a design approach approach, but some programmers do.
get() is callable by non const objects which are allowed to mutate, you can do:
S r(0);
r.get() = 1;
but if you make r const as const S r(0), the line r.get() = 1 no longer compile, not even to retrieve the value, that's why you need a const version const T& get() const to at least to able to retrieve the value for const objects, doing so allows you do:
const S r(0)
int val = r.get()
The const version of member functions try to be consistent with the constness property of the object the call is made on, i.e if the object is immutable by being const and the member function returns a reference, it may reflect the constness of the caller by returning a const reference, thus preserving the immutability property of the object.
It depends on the purpose of S. If it's some kind of a thin wrapper, it might be appropriate to allow the user to access the underlaying value directly.
One of the real-life examples is std::reference_wrapper.
No. If a getter simply returns a non-const reference to a member, like this:
private:
Object m_member;
public:
Object &getMember() {
return m_member;
}
Then m_member should be public instead, and the accessor is not needed. There is absolutely no point making this member private, and then create an accessor, which gives all access to it.
If you call getMember(), you can store the resulting reference to a pointer/reference, and afterwards, you can do whatever you want with m_member, the enclosing class will know nothing about it. It's the same, as if m_member had been public.
Note, that if getMember() does some additional task (for example, it doesn't just simply return m_member, but lazily constructs it), then getMember() could be useful:
Object &getMember() {
if (!m_member) m_member = new Object;
return *m_member;
}

Keyword 'const' on functions imply a full read-only of the object fields?

Having the following object
class Parser
{
public:
Parser(ComponentFactory * const factory): _factory(factory) {};
~Parser() = default;
void parse() const {
_factory->setFoo("foo");
}
private:
Factory * _factory;
};
My function parse() is specified as const. That's to say the function shouldn't modify the current object state and performs only read-only logics.
However, does the modification of the factory object imply a change of my current object's state? In other therms, is this even compilable?
I would like to understand why if yes, since I can't find any related subject on the net..
EDIT:
Since none can understand this, let me try to explain it better. In simple words, is the above code supposed to compile?
However, does the modification of the factory object imply a change of my current object's state?
No
In other therms, is this even compilable?
Yes.
I would like to understand why if yes, since I can't find any related subject on the net..
Say you have
struct Foo
{
int* ptr;
Foo() : ptr(new int(0)) {}
// It is valid since it does not change the state of Foo.
// It does not change where ptr points to. It just changes
// the value of what ptr points to.
void set(int value) const { *ptr = value; }
};
The compiler gives you the basic const characteristics. Higher level const-ness needs to be implemented by classes themselves.
In the case of Foo, if changing the value of what ptr to is deemed to change the state of Foo by the creator of Foo, then you'll have to remove const qualifier from the member function.
Marking a function as const means that you can't:
change any of the values of this's ivars
call a non-const function on this or any of its ivars
E.g. it would treat int foo; as const int foo;
These properties aren't transitive to pointers. Factory *_factory; doesn't become const Factory *_factory;, it becomes Factory *const _factory;, which is what you already have.
Imagine if you were using a smart pointer instead, would you expect the compiler to know that it should convert std::shared_ptr<Factory> _factory; into std::shared_ptr<const Factory> _factory;? All it would do is treat it as const std::shared_ptr<Factory> _factory;

How to deal with initialization of non-const reference member in const object?

Let's say you have a class
class C
{
int * i;
public:
C(int * v):i(v) {};
void method() const; //this method does not change i
void method(); //this method changes i
}
Now you may want to define const instance of this class
const int * k = whatever;
const C c1(k); //this will fail
but this will fail because of non-const int C's constructor C(int * v)
so you define a const int constructor
C(const int * v):i(v) {}; //this will fail also
But this will fail also since C's member "int * i" is non-const.
What to do in such cases? Use mutable? Casting? Prepare const version of class?
edit: After discussion with Pavel (below) I investigated this problem a bit. To me what C++ does is not correct. Pointer target should be a strict type, that means that you could not for example do the following:
int i;
const int * ptr;
ptr = & i;
In this case language grammar treats const as a promise not to change pointer's target. In addition int * const ptr is a promise not to change pointer value itself. Thus you have two places where const can be applied. Then you may want your class to model a pointer (why not). And here things are falling into pieces. C++ grammar provides const methods which are able to promise not to change field's values itself but there is no grammar to point out that your method will not change targets of your in-class pointers.
A workaround is to define two classes const_C and C for example. It isn't a royal road however. With templates, their partial specializations it's hard not to stuck into a mess. Also all possible arguments variations like const const_C & arg, const C & arg, const_C & arg, C & arg don't look pretty. I really don't know what to do. Use separate classes or const_casts, each way seems to be wrong.
In both cases should I mark methods which don't modify pointer's target as const? Or just follow traditional path that const method doesn't change object's state itself (const method don't care about pointer target). Then in my case all methods would be const, because class is modelling a pointer thus pointer itself is T * const. But clearly some of them modify pointer's target and others do not.
Sounds like you want an object that can wrap either int* (and then behave as non-const), or int const* (and then behave as const). You can't really do it properly with a single class.
In fact, the very notion that const applied to your class should change its semantics like that is wrong - if your class models a pointer or an iterator (if it wraps a pointer, it's likely to be the case), then const applied to it should only mean that it cannot be changed itself, and should not imply anything regarding the value pointed to. You should consider following what STL does for its containers - it's precisely why it has distinct iterator and const_iterator classes, with both being distinct, but the former being implicitly convertible to the latter. As well, in STL, const iterator isn't the same as const_iterator! So just do the same.
[EDIT] Here's a tricky way to maximally reuse code between C and const_C while ensuring const-correctness throughout, and not delving into U.B. (with const_cast):
template<class T, bool IsConst>
struct pointer_to_maybe_const;
template<class T>
struct pointer_to_maybe_const<T, true> { typedef const T* type; };
template<class T>
struct pointer_to_maybe_const<T, false> { typedef T* type; };
template<bool IsConst>
struct C_fields {
typename pointer_to_maybe_const<int, IsConst>::type i;
// repeat for all fields
};
template<class Derived>
class const_C_base {
public:
int method() const { // non-mutating method example
return *self().i;
}
private:
const Derived& self() const { return *static_cast<const Derived*>(this); }
};
template<class Derived>
class C_base : public const_C_base<Derived> {
public:
int method() { // mutating method example
return ++*self().i;
}
private:
Derived& self() { return *static_cast<Derived*>(this); }
};
class const_C : public const_C_base<const_C>, private C_fields<true> {
friend class const_C_base<const_C>;
};
class C : public C_base<C>, private C_fields<false> {
friend class C_base<C>;
};
If you actually have few fields, it may be easier to duplicate them in both classes rather than going for a struct. If there are many, but they are all of the same type, then it is simpler to pass that type as a type parameter directly, and not bother with const wrapper template.
Your example doesn't fail, k is passed by value. The member i is 'implicitly constant' as direct members of C can't be changed when the instance is constant.
Constness says that you can't change members after initialization, but initializing them with values in the initialization list is of course allowed - how else would you give them a value?
What doesn't work is invoking the constructor without making it public though ;)
update addressing updated question:
Yes, C++ forces you into some verboseness sometimes, but const correctness is a common standard behaviour that you can't just redefine without breaking expectations. Pavels answer already explains one common idiom, which is used in proven libraries like the STL, for working around this situation.
Sometimes you have to just accept that languages have limitations and still deal with the expectations of the users of the interface, even if that means applying an apparently sub-optimal solution.
Your question does not make sense. Where did you get all these "this will fail" predictions? None of them are even remotely true.
Firstly, it is completely irrelevant whether the constructor's parameter is declared const or not. When you are passing by value (as in your case) you can pass a const object as an argument in any case, regardless of whether the parameter is declared as const or not.
Secondly, from the constructor's point of view, the object is NOT constant. Regardless of what kind of object you are constructing (constant or not), from within the constructor the object is never constant. So there's no need for mutable or anything.
Why don't you just try compiling your code (to see that nothing will fail), instead of making strange ungrounded predictions that something "will fail"?
A const int* is not the same as a int* const. When your class is const, you have the latter (constant pointer to mutable integer). What you're passing is the former (mutable pointer to constant integer). The two are not interchangeable, for obvious reasons.
When you instantiate
const C c1(...)
Because c1 is const, its member i turns in to:
int* const i;
As someone else mentioned, this is called implicit const.
Now, later in your example, you attempt to pass a const int*. So your constructor is basically doing this:
const int* whatever = ...;
int* const i = whatever; // error
The reason you get an error is because you can't cast const to non-const. The 'whatever' pointer is not allowed to change the thing it points to (the int part is const). The 'i' pointer is allowed to change what it points to, but cannot itself be changed (the pointer part is const).
You also mention wanting your class to model a pointer. The STL does this with iterators. The model some implementations use is having a class called 'const_iterator' which hides the real pointer and only supplies const methods to access the pointed-to data. Then there's also an 'iterator' class which inherits from 'const_iterator', adding non-const overloads. This works nicely - it's a custom class which allows the same constness as pointers, where the types mirror pointers like so:
iterator -> T*
const iterator -> T* const
const_iterator -> const T*
const const_iterator -> const T* const
Hopefully that makes sense :)
OK here's what I have done so far. To allow inheritance after const version of class without const_casts or additional space overhead I created an union which basically looks like ths:
template <typename T>
union MutatedPtr
{
protected:
const T * const_ptr;
T * ptr;
public:
/**
* Conversion constructor.
* #param ptr pointer.
*/
MutatedPtr(const T * ptr): const_ptr(ptr) {};
/**
* Conversion to T *.
*/
operator T *() {return ptr;}
/**
* Conversion to const T *.
*/
operator const T *() const {return const_ptr;}
};
When MutatedPtr field is declared, it ends up so that in const methods const_ptr is returned, while non-const ones get plain ptr. It delegates method's const-ness to pointer target which makes sense in my case.
Any comments?
BTW you can of course do similar thing with non-pointer types or even methods, so it looks that introducing mutable keyword wasn't necessary(?)
I've run into the same unfortunate issue and after lamenting the lack of a const constructor in C++ I've come to the conclusion that two templatization is the best course, at least in terms of reuse.
A very simplified version of my case/solution is:
template< typename DataPtrT >
struct BaseImage
{
BaseImage( const DataPtrT & data ) : m_data( data ) {}
DataPtrT getData() { return m_data; } // notice that if DataPtrT is const
// internally, this will return
// the same const type
DataPtrT m_data;
};
template< typename DataPtrT >
struct DerivedImage : public BaseImage<DataPtrT>
{
};
There is a very unfortunate loss of class inheritance but in my case it was acceptable to make a sort of casting operator to be able to cast between const and non-const types with some explicit knowledge of how to do the conversion under the hood. That mixed with some appropriate use of copy constructors and/or overloaded dereference operator might get you to where you want to be.
template< typename OutTypeT, typename inTypeT )
image_cast< shared_ptr<OutTypeT> >( const shared_ptr<InTypeT> & inImage )
{
return shared_ptr<OutTypeT>( new OutTypeT( inImage->getData() ) );
}