3

Can the const_cast be used for creating non-const versions of already implemented methods? I think I saw something along these lines (with recommendation for the const method to do the actual work), but I'm not really sure how it's supposed to work.

Value& const search(key) const {
    // find value with key
    return value;
}

Value& search(key) {
    return const_cast<Value&>(search(key));
}

If not this way, what is recommended way of creating non-const functions without code duplicity?

ValentaTomas
  • 260
  • 3
  • 11
  • 1
    First of all, look up the word "duplicity." It does not mean "duplication." I'll wait.... Okay. Casting away const is something you usually do only when you find yourself in a bad predicament and up against a deadline. There are exceptions. For example, if a class has a cache that is transparent to the public. When const was introduced into the language, there was a debate as to whether "const" should mean really, really constant, or "as if" constant. "As if" won, and thus casting away const was born. – Jive Dadson Dec 17 '17 at 01:19
  • Related: https://stackoverflow.com/q/123758/1896169 – Justin Dec 17 '17 at 02:18

2 Answers2

4

The easiest way to do it is with as_const from C++17:

Value& search(key) {
    return const_cast<Value&>(std::as_const(*this).search(key));
}

Without it you can do this instead (or implement it yourself, it's not very hard)

Value& search(key) {
    return const_cast<Value&>(static_cast<const T&>(*this).search(key));
}

Where T is the type of your class (you can have a generic solution with decltype but it gets really ugly due to decltype(*this) being a reference type).

You can take a look at the as_const implementation here or the generic cast here.

user975989
  • 2,578
  • 1
  • 20
  • 38
  • 1
    Are there any other ways to do it, compatible with C++14? – ValentaTomas Dec 16 '17 at 23:00
  • You can cast `this` to the correponding `const` pointer or define tour own version of `as_const()`, e.g., `template T const& as_const(T const& x) { return x; }`. Personally I dislike casting `const` away and I’d rather implement a templaize algorithm potentially using `static` or `friend` functions and return its result in the `const`/non-`const` overloads. – Dietmar Kühl Dec 16 '17 at 23:06
  • We try to follow the coding rule "Avoid code duplication", but end up violating the rule "Avoid casting". – Bo Persson Dec 17 '17 at 07:19
1

Two approaches.

First:

namespace notstd{ // backported C++17
  template<class T>
  T const& as_const(T& t){return t;}
  template<class T>
  T const&& as_const(T&& t){return t;}      
}
namespace utility { // not ever in std
  template<class T>
  T& remove_const(T const& t){return const_cast<T&>(t);}
  template<class T>
  T&& remove_const(T const&& t){return const_cast<T&&>(t);}
}

then:

Value& const search(Key key) const {
  // find value with key
  return value;
}

Value& search(Key key) {
  return utility::remove_const(notstd::as_const(*this).search(key));
}

or alternatively:

Value& const search(Key key) const {
  return search(*this, key);
}

Value& search(Key key) {
  return search(*this, key);
}
private:
  template<class Self>
  friend decltype(auto) search(Self& self, Key key){
    // find value with key
  }

where we delegate the work to a friend template where self is maybe-const.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524