4
\$\begingroup\$

Motivation

const_cast is a beast that I seldomly encounter. But when I do so it is mostly a bad experience.

Nobody knows what most of the C++ programmers do but so far I only ever had one use for const_cast: to cast away a const from a type. For this task const_cast is too verbose:

const std::vector<int> constVectorOfInts = {/*...*/};
// never do this in real code!
auto &mutableVectorOfInts = const_cast<std::vector<int>>(constVectorOfInts);

IMHO, there is no gain in readability when repeating the type.

Enter my proposal:

unconst_cast

We can write a template function unconst_cast that solves only the problem of removing const.

/**
 * @brief Returns a mutable reference to the same object
 */
template <class T> T &unconst_cast(const T &v) { return const_cast<T &>(v); }

/**
 * @brief Returns a mutable pointer to the same object
 */
template <class T> T *unconst_cast(const T *v) { return const_cast<T *>(v); }

int main() {
  int i;
  const int *constPointerToI = &i;
  int *unconstPointerToI = unconst_cast(constPointerToI);
  unconstPointerToI = unconst_cast(&i);
  int &unconstReferenceToI = unconst_cast(*constPointerToI);
  int &unconstReferenceToI2 = unconst_cast(i);
}

Our code from above would become:

auto &mutableVectorOfInts = unconst_cast(constVectorOfInts);

Other pros:

  • can overload for other types (in contrast to const_cast), e.g. for own iterators (mutableIterator = unconst_cast(constIterator))
  • we find usages when string searching for "const_cast"

Review Goals

  • Is this a bad idea?
  • Is my implementation correct?
  • Is the naming alright/understandable?
\$\endgroup\$
  • 2
    \$\begingroup\$ Removing const is such a dangerous activity that I want it to be big ugly and stand out so that it is easy to see find and check. Any code that makes removing const easy is in my opinion dangerous. Also the use case is so infrequent that it has no real benefit. \$\endgroup\$ – Martin York Sep 2 '15 at 14:22
  • \$\begingroup\$ @LokiAstari: This is basically the argument I made below utnapistim's post. Most of the visibility of const_cast for me is the different highlighting by the IDE. Without that I would argue that const_cast can actually be less visible because it drowns in the "template" argument (see my comment). \$\endgroup\$ – Nobody Sep 2 '15 at 14:56
6
\$\begingroup\$

•Is this a bad idea?

It is unnecessary.

Nobody knows what most of the C++ programmers do but so far I only ever had one use for const_cast: to cast away a const from a type.

You can also use it to partially take away constness:

int do_things(const char* p);

const char* const xyz = "abc";
do_things( const_cast<const char*>(xyz) );

The gain in readability comes from the result type being explicitly specified.

If you have APIs that only work for non-const pointers when they should work for const (this is the most legitimate use for const_cast) you should wrap them and centralize/localize/hide the call to const_cast.

If you find yourself writing const_cast calls again and again, the problem is not poor readability of the code, but bad API design.

\$\endgroup\$
  • \$\begingroup\$ You can also use it to partially take away constness. Yes, you can also cast away volatile and so on but my main problem is to cast away the outermost const in templatized contexts where it is a real nuisance to write code like const_cast<typename std::remove_const<std::iterator_traits<ConstIterator>::reference>::type>(*constIterator); (ad hoc, constructed example). You are right in that it should be necessary rather seldomly but sometimes it is and I want to optimize that. \$\endgroup\$ – Nobody Sep 2 '15 at 13:46
  • \$\begingroup\$ Despite my comment above +1 for pointing to the API problems. Making const_cast easier to use also invites more frequent usage. \$\endgroup\$ – Nobody Sep 2 '15 at 13:55
  • \$\begingroup\$ The example you give for “partially casting away const” is unnecessary. do_tings takes the pointer by-value. The copy will not be const qualified and you could (and should) call do_things(xyz) directly. \$\endgroup\$ – 5gon12eder Feb 1 '16 at 22:47
  • \$\begingroup\$ You are correct. I checked on coliru (if the last line is uncommented, the code will not compile) \$\endgroup\$ – utnapistim Feb 2 '16 at 8:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.