Can an object know its own constness?

c++, c++11, const-correctness, reflection, type-traits

Solution

As others have stated, you cannot tell if an object was declared as `const` from within a member function. You can only tell if it's being called in a `const` context, which is not the same.

MOTIVATION: I want to be able to detect whether a const member function is invoked on a const object or is coming from a non-const object. The object could e.g. represent a cache and the member a view. If the cache was const, one could presumably use an optimized draw routine, whereas if the underlying data was non-const, the draw routine would need to do periodically check if the data was refreshed.

You can't tell that reliably.

struct A
{
  void draw() { fut = std::async(&A::do_draw, this, false); }
  void draw() const { fut = std::async(&A::do_draw, this, true); }
  void update(Data&);
private:
  void do_draw(bool this_is_const) const;
  mutable std::future<void> fut;
};

A a;
const A& ca = a;
ca.draw();           // object will think it's const, but isn't
Data new_data = ...;
a.update(new_data);  // do_draw() should recheck data, but won't

You can model it in the type system, by defining separate mutable and immutable types.

struct Base
{
  virtual ~Base();
  virtual void draw() const = 0;
protected:
  void do_draw(bool) const;
};

struct MutableCache : Base
{
  virtual void draw() const { fut = std::async(&Base::do_draw, this, false); }
  void update();
};

struct ImmutableCache : Base
{
  virtual void draw() const { fut = std::async(&Base::do_draw, this, true); }
  // no update function defined, data cannot change!
};

Now if a cache is create as an `ImmutableCache` you know it can't change, so that replaces your previous idea of a "const" object. A `MutableCache` can change, so needs to check for refreshed data.

Problem

With `decltype` and `std::is_const` the constness of a variable can be externally detected. But is it also possible for an object to know its own constness? Usage should be like: ``` #include <type_traits> #include <iostream> #include <ios> struct Test { Test() {} bool print() const { // does not work as is explained in https://stackoverflow.com/q/9890218/819272 return std::is_const<decltype(*this)>::value; // <--- what will work?? } }; int main() { Test t; const Test s; // external constness test std::cout << std::boolalpha << std::is_const<decltype(t)>::value << "\n"; std::cout << std::boolalpha << std::is_const<decltype(s)>::value << "\n"; // internal constness test std::cout << std::boolalpha << t.print() << "\n"; std::cout << std::boolalpha << s.print() << "\n"; // <--- false?? } ``` Output on LiveWorkSpace Is this somehow possible? MOTIVATION: I want to be able to detect whether a const member function is invoked on a const object or is coming from a non-const object. The object could e.g. represent a cache and the member a view. If the cache was const, one could presumably use an optimized draw routine, whereas if the underlying data was non-const, the draw routine would need to do periodically check if the data was refreshed. NOTE: the related question asks how to break the build for const objects, but I don't quite understand if the answer to that implies a definite NO for my question. If not, I want to capture the constness in a boolean for further usage. EDIT: as was pointed out @DanielFrey, the constructor is not a good place to test for constness. What about a const member function? UPDATE: Thanks everyone for correcting my initially ill-posed question and providing the various parts of the answer (constructors' ill-defined constness, rvaluedness of `this`, the contextual meaning of `const`, the -with hindsight- obvious overload trick that I had overlooked, and the const reference aliasing loophole lurking in the shadows). For me this question was Stackoverflow at its best. I decided to select @JonathanWakely's answer because it showed how to define `Mutable` and `Immutable` classes that strengthen the constness concept to achieve what I want in a foolproof way.

Original source

Related problems