Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate a non-const method from a const method?

While striving for const-correctness, I often find myself writing code such as this

class Bar;

class Foo {
public:
  const Bar* bar() const { /* code that gets a Bar somewhere */ }

  Bar* bar() {
    return const_cast< Bar* >(
      static_cast< const Foo* >(this)->bar());
  }
};

for lots of methods like bar(). Writing these non-const methods which call the const ones by hand is tedious; besides, I feel I am repeating myself – which makes me feel bad.

What can I do to alleviate this task? (Macros and code generators are not allowed.)

Edit: Besides litb's solution I also like my own. :)

like image 778
Tobias Avatar asked Aug 26 '09 10:08

Tobias


People also ask

How do you call a non-const method from the const method?

Casting away const relies on the caller only using the function on non-const objects. A potential solution is to alter the code in // .... so that it doesn't need to use the object's "current color". Add versions of all the functions you use, that take a QColor parameter instead.

Can you call a non-const function from a const function?

const function use cases A const function can be called by either a const or non- const object. Only a non- const object can call a non- const function; a const object cannot call it.

Can const methods be used by non-const objects?

const member functions may be invoked for const and non-const objects. non-const member functions can only be invoked for non-const objects. If a non-const member function is invoked on a const object, it is a compiler error.

Can we invoke non-const member function using a pointer reference to const?

Yes, in the sense that it can be const_cast away, or the object can have mutable members.


3 Answers

Another way could be to write a template that calls the function (using CRTP) and inherit from it.

template<typename D>
struct const_forward {
protected:
  // forbid deletion through a base-class ptr
  ~const_forward() { }

  template<typename R, R const*(D::*pf)()const>
  R *use_const() {
    return const_cast<R *>( (static_cast<D const*>(this)->*pf)() );
  }

  template<typename R, R const&(D::*pf)()const>
  R &use_const() {
    return const_cast<R &>( (static_cast<D const*>(this)->*pf)() );
  }
};

class Bar;

class Foo : public const_forward<Foo> {
public:
  const Bar* bar() const { /* code that gets a Bar somewhere */ }
  Bar* bar() { return use_const<Bar, &Foo::bar>(); }
};

Note that the call has no performance lost: Since the member pointer is passed as a template parameter, the call can be inlined as usual.

like image 159
Johannes Schaub - litb Avatar answered Sep 18 '22 23:09

Johannes Schaub - litb


Use following trick:


class Bar;
class Foo {
public:  
  Bar* bar() { 
    // non-const case
    /* code that does something */ 
  }  
  const Bar* bar() const {    
      return This().bar();  // use non-const case
   }

private:
  //trick: const method returns non-const reference
  Foo & This() const { return const_cast<Foo &>(*this); } 
};

Note it is possible to use unique function This for any const/non-const functions.

Alternative solution without static_cast (but I prefer the first one):

class Bar;
class Foo {
public:  
  const Bar* bar() const { /* code that does something */ }  
  Bar* bar() { return const_cast<Bar*>(cthis().bar()); } // use const case
private:
  const Foo & cthis() const { return *this; } 
};
like image 34
Alexey Malistov Avatar answered Sep 18 '22 23:09

Alexey Malistov


You can do something like this:

class Bar;

class Foo {
public:
  const Bar* bar() const { return getBar(); }

  Bar* bar() {
   return getBar();
  }

  private:
    Bar* getBar() const {/* Actual code */ return NULL;}
};
like image 33
Naveen Avatar answered Sep 19 '22 23:09

Naveen