10

Using C++ style typecastings (all 4) look exactly like some function template. e.g.

template<typename TO, typename FROM> TO dynamic_cast (FROM p); 

will be used as,

dynamic_cast<Derived*>(p); // p is Base* 

Why is it not allowed to overload them by language standard for custom usage ? (like we can overload the keywords like new/delete or other operators)

5
  • Interestingly, some libraries (like Boost) use this similarity to define their own "casting" operators, like static_pointer_cast<>. Commented May 12, 2011 at 8:09
  • @ereOne, ya I heard of some casts like that, but this keyword are not allowed for some reason !! Commented May 12, 2011 at 8:17
  • Put a rule in your project that all casts will take place via some forwarding templates: "x_dynamic_cast", "x_static_cast" etc. Then search for any use of the real dynamic_cast and replace it. This is one of the cool features of the "wordy" cast operators in that they're very easy to search for. Commented May 12, 2011 at 9:05
  • Since there are some answers that pretty much cover the why part I just wanted to say well maybe it is not allowed, but you can replace dynamic_cast. You can define your templated "my_cast" and then use the preprocessor to replace dynamic_cast or reinterpret_cast a.s.o let's say in debug builds (i.e. in the same way you can use the preprocessor to "rename" new to DEBUG_NEW). We did this do add some compile time checks in debug builds related to casting. We had the advantage that we had a header file that was included over all so we could '#define dynamic_cast chk:my_cast' in a single place Commented May 12, 2011 at 9:15
  • The advantage I see with the preprocessor aproach (compared to replacing by search and replace dynamic_cast with x_my_dynamic_cast is that it doesn't forces everyone in your team to write x_my_dynamic_cast, and also makes sure that situations where someone forgets (or doesn't yet know - i.e. is new in the team) that x_my_dynamic_cast instead of dynamic_cast should be used are automatically provided for. And everyone can write the code as they normally would... Commented May 12, 2011 at 9:20

4 Answers 4

3

Why is it not allowed to overload them by language standard for custom usage?

I suppose that's because the standard committee, when introducing these, thought the semantics of all four of these casts are well defined, and applicable to all types they should be. And mostly, this is true.

The only counter example I know of is the inability to dynamic_cast between smart pointer instances:

shared_ptr<Derived> pd = dynamic_cast<shared_ptr<Derived> >(pb); 

I suppose the ability to do that would have some merits.

I don't know whether this has been discussed by the volunteers that did all the work in the standards committee (and I'm too lazy to google), but if it has been discussed (and I'd think so), it's been rejected either because someone thought the disadvantages outweigh the advantages, or because nobody had found the time to make a decent proposal and shepherd it through.1


1 Don't laugh. There's actually a lot of things most agree would be nice to have, and which are only failing to materialize because nobody could be bothered to do the work of writing a decent proposal, and spending the time needed to discuss and to iteratively improve it until it can be voted on.

Sign up to request clarification or add additional context in comments.

8 Comments

+1, I took it seriously. :) I feel that any casting should be allowed to be overloaded. Even though their standard decent implementations are available. e.g. I want to put a debug when someone tries reinterpret_cast.
@iammilind: There's no point in overloading, say static_cast. What would you want to do in an overloaded version? The same goes for reinterpret_cast. It's there for doing unsafe, platform-dependent casts. What would you want to add to that which it doesn't already do? And don't get me started about const_cast. Everything I could possibly imagine doing with an overload of that should be doable with proper const-correct code.)
You can already affect static_cast by providing a converting constructor or a convertion operator for it to use.
@BoPersson: Yeah, I forgot to mention that. Thanks.
I also see no sense in overloading static_cast, reinterpret_cast and const_cast...but overloading dynamic_cast is something I also wish I would have.
|
2

I think the reason is the same for you can't overload language keyword.

In fact, you have to see them as language keyword and not template function, even if the look the same. OTOH, I couldn' imagine what kind of disasters one could do by changing the meaning of this particular C++ aspect.

EDIT
I was pretty sure that someone would have come up with the question: "then why you can overload new/delete?". I think that memory allocation/deallocation customization is something that you need in certain scenarios, and the benefits of allowing you to overload them outweighs the risks. I can't see any advantage in subverting the C++ type system, IOW I fail to think a scenario where it would be useful. Do you?

9 Comments

new/delete are also language keyword and ppl can do disasters in them; same thing is applicable for overloading operator. Then why not typecasts, which exactly look like functions already.
shared_ptr<Derived> pd = dynamic_cast<shared_ptr<Derived> >(pb)
yes, dynamic_cast can be optimized if a developer knows that his class is inherited by only one other class (with virtual function). There are many such usefulness I can count for other casts
@iammilind if you need to optimize your code, I wouldn't focus on type cast. I really have hard-time thinking it as a bottleneck...
@Simone, sometimes your class might be used by others. You can't ask them not to use dynamic_cast; rather you can simply overload it. Also, i just gave an example .. there can be many such usefulness.
|
2

Pointer conversion with dynamic_cast, reinterpret_cast and static_cast have well defined meanings and it is probably better not to allow overloading.
It would be a pain to allow users to change the meaning of const_cast.

Only object type casting remains.

struct A { A() {}; template <typename FROM> A(FROM&) { std::cout << "Casting to A \\o/" << std::endl; } template <typename TO> operator TO() { std::cout << "Casting from A \\o/" << std::endl; return TO(); } }; 

then

 int i; A a; A toA = static_cast<A>(i); // Casting to A \o/ int fromA = static_cast<int>(a); // Casting from A \o/ 

Hopefully you have better use cases than mine :)

Comments

1

You cannot overload these operators. It is, arguably, because you cannot change the meaning of such a fundamental thing as other answers say. (Like changing the meaning for + for integers, or the * decoration to generate a pointer from a type).

Having said that, nothing prevents you from defining your own generalizations of cast functions, that take an argument and return things very related to it. Actually, I would argue the opposite point of view, you should never use the language cast operations (static/dynamic/reinterpret_cast) unless you are doing pretty low level stuff.

What you would want to do probably is to define your own casting function that most of the time behaves like the ones provided by the language but once in a while they do something more specific for your specific purposes. You have to think hard what this function really does and name it well. What kind of runtime cost you can afford, what kind of behavior on "failure" (throw execption?, return a null value?), etc.

The standard and many libraries are full of such functions. Sometimes they add a tweaked behavior over language cast, other times they do more. Some examples:

https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast

  • std::static_pointer_cast,
  • std::dynamic_pointer_cast,
  • std::const_pointer_cast,
  • std::reinterpret_pointer_cast

  • std::any_cast

  • std::chrono::time_point_cast

(see also https://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/pointer_cast.html)

https://www.boost.org/doc/libs/1_42_0/libs/conversion/lexical_cast.htm

  • boost::lexical_cast

https://www.boost.org/doc/libs/1_63_0/libs/conversion/cast.htm

  • polymorphic_cast,
  • polymorphic_downcast,
  • polymorphic_pointer_cast
  • polymorphic_pointer_downcast

https://www.boost.org/doc/libs/1_72_0/libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html

  • boost::numeric_cast

https://www.boost.org/doc/libs/1_47_0/doc/html/boost_units/Quantities.html#boost_units.Quantities.Quantity_Construction_and_Conversion

  • boost::units::quanity_cast.

Sometimes they are not called cast at all :)

https://en.cppreference.com/w/cpp/utility/variant/get_if

  • std::get_if

Another example, for template code I wrote this cast function that is only invoked if the conversion can be done implicitly:

 template<class To, class From, std::enable_if_t<std::is_convertible<From, To>{}, int> =0> To implicit_cast(From&& f){ return static_cast<To>(f); } 

https://godbolt.org/z/ym8MnJ

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.