Const and non-const access resolves to different overloads? - c++

Let me say we have a simple programming task. But for the sake of clarity I start with few code samples.
First of all we written a some kind of data container class but for the purposes of task no matter what the class is. We just need it to behave const-correct.
class DataComponent {
public:
const std::string& getCaption() const {
return caption;
}
void setCaption(const std::string& s) {
caption = s;
}
private:
std::string caption;
};
Then let us assume we've got a generic class that behaves like facade over arbitrary incapsulated class instance. Say we overloaded member access operator (->).
template <typename T> class Component {
public:
Component() { instance = new T(); }
...
const T* operator-> () const {
return instance;
}
T* operator-> () {
// but there might be additional magic
return instance;
}
private:
T *instance;
};
At this point I should say how I want this to work:
if we're calling non-const member functions of underlying class through member access operator (component->setCaption("foo")) compilier treats non-const T* operator-> () as the best choice.
otherwise if we are trying to call const member functions of underlying class same way (component->getCaption()) compiliers selects const T* operator-> () const on the other hand.
This code sample above won't work this way so I'm curious about possibility to give compiler a behavior like that I have mentioned. Any propositions.
EDIT: Let our member access operator overloaded this way:
const T* operator-> () const { return instance; }
T* operator-> () {
cout << "something going change" << endl;
return instance;
}
And let us have a variable Component<DataComponent> c somewhere. Then on the call to c->getCaption() stdout should remain silent but on the call to c->setCaption("foo") stdout should warn us that something is going to change. VS 2010 compilier makes stdout warn us on each of these calls.
I understand that such semantics suppose that c behaves as const and non-const at the same time. But curiousity is still in my mind.

Whether a const or non-const member is invoked is determined purely by the constness of the object on which it is invoked, not by some subsequent operation. That determination is made before any consideration of the particular method you're invoking in DataComponent. You could still hack up the required functionality less directly using proxy object around DataComponent, with both const and non-const forwarding getCaption()s.
EDIT: details as requested (off the top of my head). You'll need to forward declare some of this stuff - I didn't bother as it makes it even more confusing. Do chip in with any concerns / feedback. Note that this basically assumes you can't / don't want to modify Component for some reason, but it's not a generic templated solution that can simply be wrapped around any arbitrary type - it's very heavily coupled and has a high maintenance burden.
// know they can't call a non-const operation on T, so this is ok...
const T* Component::operator->() const { return instance; }
// they might invoke a non-const operation on T, so...
DataComponent::Proxy Component::operator->() { return DataComponent.getProxy(*this); }
in class DataComponent:
struct Proxy
{
Component& c_;
DataComponent& d_;
Proxy(Component& c, DataComponent& d) : c_(c), d_(d) { }
const std::string& get_caption() const { return d_.get_caption(); }
void set_caption(const std::string& s)
{
c_.on_pre_mutator(d_);
d_.set_caption(s);
c_.on_post_mutator(d_);
}
};
then
DataComponent::Proxy DataComponent::getProxy(Component& c) { return Proxy(c, *this); }
So, this means somewhere you have to hand-code forwarding functions. It's a pain, but if you're doing this for debugging or testing it's not unreasonable. If you're doing this so you can add a lock or something, then there are probably better alternatives.

Related

Constant version of a concept as return type in requires clause

I have some class A that has some const and some non-const function, together with a fitting concept, say
class A {
public:
void modify() {/* ... */}
void print() const {/* ... */}
}
template<typename T>
concept LikeA = requires (T t, const T const_t) {
{ t.modify() } -> std::same_as<void>;
{ const_t.print() } -> std::same_as<void>;
}
static_assert(LikeA<A>);
A nice thing I noticed is that for some function taking const LikeA auto &a below code is actually legal:
void use (const LikeA auto &a) {
a.print(); // fine, print is a const method
// a.modify(); // illegal, a is a const reference [at least for use(A a) itself, but this is not my point here]
}
static_assert(!LikeA<const A>);
int main() {
A a1;
use(a1); //clear, as LikeA<A> holds
const A a2;
use(a2); //not obvious, as LikeA<const A> does not hold
}
I looked into the definitions on cppreference, and I could not really explain this behaviour, I expected it to be illegal, although intuitively, this really is what I want.
Now on to my real situation: I have a holder class AHolder that returns const A& as one of its methods, and I want a fitting concept for this holder class that also applies to any other holder holding anything that satisfies LikeA, so I tried:
class AHolder {
public:
const A& getA() {return _a;}
private:
const A _a;
};
template<typename T>
concept LikeAHolder = requires (T t) {
{t.getA() } -> LikeA;
};
static_assert(LikeAHolder<AHolder>); //fails
This fails, since const A& simply doesn't satisfy LikeA, so i would love to adjust this to
template<typename T>
concept LikeAHolder = requires (T t) {
{t.getA() } -> const LikeA; //invalid syntax
};
static_assert(LikeAHolder<AHolder>);
in similar spirit of the example with the use method also accepting const A.
Is there such a syntax to require the return type of t.getA to satisfy LikeA whilst considering that the return type will be const?
Additionally, how exactly are concepts checked in the use(const LikeA auto &a) method such that it behaves like explained?
(My first question is the more important one for me)
Some possible solutions that I have considered:
Return a non-const-reference. This would make above code illegal, but of course would heavily ruin const-correctness, since _a would also have to be non-const and a user could just change the private attribute of AHolder. This is no option for me.
Have two concepts LikeA and LikeConstA. The return type then could be LikeConstA only requiring the const methods. This should work, but feels really clumsy and really not how concepts should be used, also this introduces more concepts that necessary to an end-user, who has to bother with them, etc.
In the concept LikeA, check whether the templated type T is constant (via std::is_const), and if so, don't require the non-const-methods. This works in above example, but has the undesired effect that we now simply have
class B {
public:
void print() const {/* ... */}
}
static_assert(LikeA<const B>);
(for an already adapted LikeA, of course), which also just feels wrong.
in the definition of LikeA, use std::remove_reference and std::const_cast to cast away references / constness, then check for the required functions. First, i don't know if this will always work for more complicated types, but even then, this now has the undesired effect that
static_assert(LikeA<const A>);
will be true, breaking (or at least bending) the semantics of the concept.
To summary and ensure you don't get me wrong, I would like to have a way that
does enforce const-correctness
does not use a second concept 'for the end-user'. With this I mean that it is of course okay to define auxiliary concepts or use some of the standard-library that help in defining above concept, but nothing that is actually required to use A and LikeA etc.
does not simply ignore non-const requirements for const types (as I mentioned, this would be compiler-wise okay, but semantically feels wrong)
does not define LikeA<const A> to be true
Ideally, there would just be a feature working like the already-mentioned
template<typename T>
concept LikeAHolder = requires (T t) {
{t.getA() } -> const LikeA; //invalid syntax
};
{[](const LikeA auto&){}( t.getA() )}
Note that a non-const& returning getA will pass this.
I made a lambda that does a concept check, then ensured t.getA() passes it.
void use (const LikeA auto &a)
This is shorthand for
template<LikeA A>
void use (const A&a)
and when called with a T const, it deduces A=T not A=T const. Why? Because it is "more correct" abstractly. Concretely, there are a pile of rules for how template argument type deduction works.

Avoid literally duplicating code for const and non-const with auto keyword?

Okay, I did some research and apparently there are a lot of duplicate questions on SO on this topic, to name a few:
Elegant solution to duplicate, const and non-const, getters?
How to avoid operator's or method's code duplication for const and non-const objects?
How do I remove code duplication between similar const and non-const member functions?
etc. But I cannot help but raise this again, because
With c++14 auto-typed return value, I am literally duplicating the function body with the only difference being the const function qualifier.
It is possible that const version and non-const version may return types that are totally incompatible from each other. In such cases, neither Scott Meyers's const_cast idiom, nor the "private const function returning non-const" technique would work.
As an example:
struct A {
std::vector<int> examples;
auto get() { return examples.begin(); }
auto get() const { return examples.begin(); }
}; // Do I really have to duplicate?
// My real-world code is much longer
// and there are a lot of such get()'s
In this particular case, auto get() returns an iterator while auto get() const returns a const_iterator, and the two cannot be converted into each other (I know erase(it,it) trick does the conversion in this case but that's not the point). The const_cast hence does not work; even if it works, that requires the programmer to manually deduce auto type, totally defeating the purpose of using auto.
So is there really no way except with macros?
Ok, so after a bit of tinkering I came up with the following two solutions that allow you to keep the auto return type and only implement the getter once. It uses the opposite cast of what Meyer's does.
C++ 11/14
This version simply returns both versions in the implemented function, either with cbegin() or if you don't have that for your type this should work as a replacement for cbegin(): return static_cast<const A&>(*this).examples.begin(); Basically cast to constant and use the normal begin() function to obtain the constant one.
// Return both, and grab the required one
struct A
{
private:
// This function does the actual getter work, hiding the template details
// from the public interface, and allowing the use of auto as a return type
auto get_do_work()
{
// Your getter logic etc.
// ...
// ...
// Return both versions, but have the other functions extract the required one
return std::make_pair(examples.begin(), examples.cbegin());
}
public:
std::vector<int> examples{ 0, 1, 2, 3, 4, 5 };
// You'll get a regular iterator from the .first
auto get()
{
return get_do_work().first;
}
// This will get a const iterator
auto get() const
{
// Force using the non-const to get a const version here
// Basically the inverse of Meyer's casting. Then just get
// the const version of the type and return it
return const_cast<A&>(*this).get_do_work().second;
}
};
C++ 17 - Alternative with if constexpr
This one should be better since it only returns one value and it is known at compile time which value is obtained, so auto will know what to do. Otherwise the get() functions work mostly the same.
// With if constexpr
struct A
{
private:
// This function does the actual getter work, hiding the template details
// from the public interface, and allowing the use of auto as a return type
template<bool asConst>
auto get_do_work()
{
// Your getter logic etc.
// ...
// ...
if constexpr (asConst)
{
return examples.cbegin();
// Alternatively
// return static_cast<const A&>(*this).examples.begin();
}
else
{
return examples.begin();
}
}
public:
std::vector<int> examples{ 0, 1, 2, 3, 4, 5 };
// Nothing special here, you'll get a regular iterator
auto get()
{
return get_do_work<false>();
}
// This will get a const iterator
auto get() const
{
// Force using the non-const to get a const version here
// Basically the inverse of Meyer's casting, except you get a
// const_iterator as a result, so no logical difference to users
return const_cast<A&>(*this).get_do_work<true>();
}
};
This may or may not work for your custom types, but it worked for me, and it solves the need for code duplication, although it uses a helper function. But in turn the actual getters become one-liners, so that should be reasonable.
The following main function was used to test both solutions, and worked as expected:
int main()
{
const A a;
*a.get() += 1; // This is an error since it returns const_iterator
A b;
*b.get() += 1; // This works fine
std::cout << *a.get() << "\n";
std::cout << *b.get() << "\n";
return 0;
}
struct A {
std::vector<int> examples;
private:
template <typename ThisType>
static auto
get_tmpl(ThisType& t) { return t.examples.begin(); }
public:
auto get() { return get_tmpl(*this); }
auto get() const { return get_tmpl(*this); }
};
How about the above? Yes, you still need to declare both methods, but the logic can be contained in a single static template method. By adding a template parameter for return type this will work even for pre-C++11 code.
Just a hypothetical solution, that I am thinking about applying every where once we will have concepts: using friend free function in place of member function.
//Forwarding ref concept
template<class T,class U>
concept FRef = std::is_same_v<std::decay_t<T>,std::decay_t<U>>;
struct A{
std::vector<int> examples;
friend decltype(auto) get(FRef{T,A}&& aA){
return std::forward<T>(aA).examples.begin();
//the std::forward is actualy not necessary here
//because there are no overload value reference overload of begin.
}
};

Call an "initialize" function in an object when one of its member functions are called

I am trying to implement lazy initializing in C++ and I am searching for a nice way to call the Initialize() member function when some other method like object->GetName() gets called.
Right now I have implemented it as follows:
class Person
{
protected:
bool initialized = false;
std::string name;
void Initialize()
{
name = "My name!"; // do heavy reading from database
initialized = true;
}
public:
std::string GetName()
{
if (!initialized) {
Initialize();
}
return name;
}
};
This does exactly what I need for the time being. But it is very tedious to setup the initialized check for every method, so I want to get rid of that. If someone knows a nice way in C++ to improve this above example, I would like to know!
Could maybe operators be used to achieve calling Initialize() when using -> for example?
Thanks!
Sounds like a job for templates! Create a lazily_initialized wrapper that takes a type T and a function object TInitializer type:
template <typename T, typename TInitializer>
class lazily_initialized : TInitializer
{// ^^^^^^^^^^^^^^
// inheritance used for empty-base optimization
private:
T _data;
bool _initialized = false;
public:
lazily_initialized(TInitializer init = {})
: TInitializer(std::move(init))
{
}
T& get()
{
if(!_initialized)
{
static_cast<TInitializer&>(*this)(_data);
_initialized = true;
}
return _data;
}
};
You can the use it as follows:
struct ReadFromDatabase
{
void operator()(std::string& target) const
{
std::cout << "initializing...\n";
target = "hello!";
}
};
struct Foo
{
lazily_initialized<std::string, ReadFromDatabase> _str;
};
Example:
int main()
{
Foo foo;
foo._str.get(); // prints "initializing...", returns "hello!"
foo._str.get(); // returns "hello!"
}
example on wandbox
As Jarod42 mentioned in the comments, std::optional<T> or boost::optional<T> should be used instead of a separate bool field in order to represent the "uninitialized state". This allows non default-constructible types to be used with lazily_initialized, and also makes the code more elegant and safer.
As the former requires C++17 and the latter requires boost, I used a separate bool field to make my answer as simple as possible. A real implementation should consider using optional, using noexcept where appropriate, and also consider exposing a const-qualified get() that returns a const T&.
Maybe call it in the constructor?
Edit: Uh, i missed the point of your question sorry.
What about a lazy factory initialization?
https://en.wikipedia.org/wiki/Lazy_initialization#C.2B.2B

Design : const and non-const accessors interdependance? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I remove code duplication between similar const and non-const member functions?
In the following example :
template<typename Type, unsigned int Size>
class MyClass
{
public: inline Type& operator[](const unsigned int i)
{return _data[i];}
public: inline const Type& operator[](const unsigned int i) const
{return _data[i];}
protected: Type _data[Size];
};
the const and non-const operator[] are implemented independently.
In terms of design is it better to have :
1) two independant implementations like here
2) one of the two function calling the other one
If solution 2) is better, what would be the code of the given example ?
It is a well-known and widely accepted implementation pattern, when non-const method is implemented through its const counterpart, as in
class some_class {
const some_type& some_method(arg) const
{
...;
return something;
}
some_type& some_method(arg)
{
return const_cast<some_type&>(
const_cast<const some_class *>(this)->some_method(arg));
}
};
This is a perfectly valid technique, which essentially has no comparable (in convenience) alternatives in situations when the method body is relatively heavy. The evil of const_cast is significantly smaller than the evil of duplicated code.
However, when the body of the method is essentially an one-liner, it might be a better idea to stick to an explicit identical implementation, just to avoid this barely readable pileup of const_casts.
One can probably come up with a formally better designed castless solution implemented along the lines of
class some_class {
template <typename R, typename C>
static R& some_method(C *self, arg)
{
// Implement it here in terms of `self->...` and `R` result type
}
const some_type& some_method(arg) const
{
return some_method<const some_type>(this, arg);
}
some_type& some_method(arg)
{
return some_method<some_type>(this, arg);
}
};
but to me it looks even less elegant than the approach with const_cast.
You couldn't have either implementation calling the other one without casting away constness, which is a bad idea.
The const method can't call the non-const one.
The non-const method shouldn't call the const one because it'd need to cast the return type.
Unfortunately, "constness" templates don't work but I still think it is worth considering the overall idea:
// NOTE: this DOES NOT (yet?) work!
template <const CV>
Type CV& operator[](unsigned int index) CV {
...
}
For the time being, I'd implement trivial functions just twice. If the code become any more complex than a line or two, I'd factor the details into a function template and delegate the implementation.

const and pointers

Edit1: I realize this is hard to understand this question without having an insight of what I'm trying to do. The class A is not complete but it essentially stand for a C-array "proxy" (or "viewer" or "sampler"). One interesting usage is too present a C-array as a 2d grid (the relevant function are not shown here). The property of this class are the following:
it should not own the data - no deep copyy
it should be copyable/assignable
it should be lightweight (
it should preserve constness (I'm having trouble with this one)
Please do not question the purpose or the design: they are the hypothesis of the question.
First some code:
class A
{
private:
float* m_pt;
public:
A(float* pt)
:m_pt(pt)
{}
const float* get() const
{
return m_pt;
}
void set(float pt)
{
*m_pt = pt;
}
};
void gfi()
{
float value = 1.0f;
const A ac(&value);
std::cout<<(*ac.get())<<std::endl;
A a = ac;
a.set(2.0f);
std::cout<<(*ac.get())<<std::endl;
}
Calling "gfi" generate the following output:
1
2
Assigning a with ac is a cheap way to shortcut the constness of ac.
Is there a better way to protect the value which m_pt point at?
Note that I DO want my class to be copyable/assignable, I just don't want it to loose its constness in the process.
Edit0: I also DO want to have a pointer in there, and no deep copy please (let say the pointer can be a gigantic array).
Edit2: thanks to the answers, I came to the conclusion that a "const constructor" would be a useful thing to have (at least in this context). I looked it up and of course I'm not the same one who reached this conclusion. Here's an interesting discussion:
http://www.rhinocerus.net/forum/language-c-moderated/569757-const-constructor.html
Edit3: Finally got something which I'm happy with. Thanks for your help. Further feedback is more than welcome
template<typename T>
class proxy
{
public:
typedef T elem_t;
typedef typename boost::remove_const<T>::type elem_unconst_t;
typedef typename boost::add_const<T>::type elem_const_t;
public:
elem_t* m_data;
public:
proxy(elem_t* data = 0)
:m_data(data)
{}
operator proxy<elem_const_t>()
{
return proxy<elem_const_t>(m_data);
}
}; // end of class proxy
void test()
{
int i = 3;
proxy<int> a(&i);
proxy<int> b(&i);
proxy<const int> ac(&i);
proxy<const int> bc(&i);
proxy<const int> cc = a;
a=b;
ac=bc;
ac=a;
//a=ac; // error C2679: binary '=' : no operator found which takes a right-hand operand of type...
//ac.m_data[0]=2; // error C3892: 'ac' : you cannot assign to a variable that is const
a.m_data[0]=2;
}
Your class is badly designed:
it should use float values, not pointers
if you want to use pointers, you probably need to allocate them dynamically
and then you need to give your class a copy constructor and assignment operator (and a destructor) , which will solve the problem
Alternatively, you should prevent copying and assignment by making the copy constructor and assignment op private and then not implementing them.
You can trick around with proxy pattern and additional run-time constness boolean member. But first, please tell us why.
Effectively your class is like an iterator that can only see one value. It does not encapsulate your data just points to it.
The problem you are facing has been solved for iterators you should read some documentation on creating your own iterator and const_iterator pairs to see how to do this.
Note: in general a const iterator is an iterator that cannot be incremented/decremented but can change the value it points to. Where as a const_iterator is a different class that can be incremented/decremented but the value it points to cannot be changed.
This is the same as the difference between const float * and float *const. In your case A is the same as float * and const A is the same as float *const.
To me your choices seem to be:
Encapsulate your data.
Create a separate const_A class like iterators do
Create your own copy constructor that does not allow copies of const A eg with a signature of A(A & a);
EDIT: considering this question some more, I think you are misinterpreting the effect of const-correctness on member pointers. Consider the following surprising example:
//--------------------------------------------------------------------------------
class CNotSoConstPointer
{
float *mp_value;
public:
CNotSoConstPointer(float *ip_value) : mp_value(ip_value) {}
void ModifyWithConst(float i_value) const
{
mp_value[0] = i_value;
}
float GetValue() const
{
return mp_value[0];
}
};
//--------------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
float value = 12;
const CNotSoConstPointer b(&value);
std::cout << b.GetValue() << std::endl;
b.ModifyWithConst(15);
std::cout << b.GetValue() << std::endl;
while(!_kbhit()) {}
return 0;
}
This will output 12 and then 15, without ever being "clever" about the const-correctness of the const not-so-const object. The reason is that only the pointer ITSELF is const, not the memory it points to.
If the latter is what you want, you'll need a lot more wrapping to get the behavior you want, like in my original suggestion below or Iain suggestion.
ORIGINAL ANSWER:
You could create a template for your array-proxy, specialized on const-arrays for the const version. The specialized version would have a const *m_pt, return a const pointer, throw an error when you try to set, and so on.
Edit: Something like this:
template<typename T>
class TProxy
{
T m_value;
public:
TProxy(T i_t) : m_value(i_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.m_value) {}
T get() { return m_value; }
void set(T i_t) { m_value = i_t; }
};
template<typename T>
class TProxy<const T *>
{
const T *mp_value;
public:
TProxy(const T *ip_t) : mp_value(ip_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.mp_value) {}
T get() { return m_value; }
};
Why not replace float* with float in A. If you don't either the original owner of the float that the float* references can change it, or anyone prepared to do a mutable cast on the return value from a::get.
const is always just a hint to the compiler; there are no ways to make a variable permanently read-only.
I think you should use deep copy and define your own assingment operator and copy constructor.
Also to return handle to internal data structure in not a good practice.
You can deny the copy-constructor for certain combinations of arguments:
For instance, adding the constructor;
A(A& a) :m_pt(a.m_pt) { m_pt = a.m_pt; }
prevents any instance of A being initialised with a const A.
This also prevents const A a2 = a1 where a1 is const, but you should never need to do this anyway, since you can just use a1 directly - it's const even if you could make a copy, a2 would be forever identical to a1.