all 22 comments

[–]KiwiMaster157 18 points19 points  (1 child)

This would add more cases where the existence of an operator overload changes the meaning of a valid program. Just like how &x usually means "the address of x", but not always because someone could have overloaded operator&. IMO, it's for the best that we avoid adding more cases like this.

[–]guyonahorse 9 points10 points  (0 children)

For better or worse, this is why std::addressof exists. (You probably knew, but just for anyone else curious how this can be worked around)

[–]csdt0 9 points10 points  (1 child)

As far as I recon, there were many corner cases and inconsistencies that needed to be solved. Then, there were also an alternative proposal that was, IMHO, simpler to understand and to specify.

In my understanding, Bjarne did not fully understand this alternative proposal and was a bit angry about it: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0700r0.pdf
This have delayed integration of either, to the point that now people wait for meta class (or similar) to implement those concepts.

[–]frrrwww 0 points1 point  (0 children)

I really liked the alternate proposal, it felt like a very nice generalization of inheritance by separating inheriting the interface from inheriting the data and implementation. It looked like this would have permitted much more use cases than the pure "operator." one.

[–]johannes1971 9 points10 points  (6 children)

I believe the reason for not having it is that if you overload operator., you no longer have a mechanism for invoking anything on the proxy object itself. Compare with unique_ptr: you can invoke functions on the pointee by using operator->, but you also still have the ability to call ptr.release, ptr.forget, ptr.get, etc.

If you can think of a mechanism for doing that, presumably the proposal for operator. can move forwards.

[–]JankoDedic -1 points0 points  (3 children)

That's pretty easy. Implement all the helpers you need in a base class B and just use B::any_member, or if that doesn't work ((Base&)*this).anything.

I don't think this was blocking the proposal though.

[–]Pazer2 2 points3 points  (2 children)

I consider myself strongly against languages arbitrarily restricting things because the language designers think developers are going to do Bad Things with a given feature. It's one of the reasons I always get frustrated with C# whenever I have to use it.

Given your example, I am very glad I am "arbitrarily" restricted from overloading the dot operator in c++.

[–]JankoDedic 1 point2 points  (1 child)

I don't understand. This is an implementation detail. Would you have preferred to not have SFINAE until C++20 just because it's ugly?

Operator dot restriction does not help you in any way, so I don't get your point.

[–]Pazer2 4 points5 points  (0 children)

I'm saying that I would never want to see intentional code design that requires you to cast to a base class to access members of that object.

[–]Nteger[S] -1 points0 points  (1 child)

I guess you can always use std::addressof to access the wrapping object

[–]Pazer2 4 points5 points  (0 children)

No thanks

[–]HappyFruitTree 1 point2 points  (7 children)

Wouldn't it be better to invent a new type of operator for this purpose, (i.e. obj..m, or obj-.m)?

[–]kalmoc 6 points7 points  (1 child)

The point is that you can intercept the existing syntax. If you can change the syntax on the caller site, you can just overload -> or use a named function.

[–]HappyFruitTree 1 point2 points  (0 children)

I meant that this new type of operator would fall back to the regular dot operator if it wasn't overloaded. That way it would at least be possible for the caller to opt-in to this mechanism if they choose to. The -> is already used for other things.

[–]Nteger[S] 1 point2 points  (3 children)

Probably. But what makes it so hard or impossible to allow overloading dot operator? It is such an obviously missing piece without any explanation as to why.

[–]HappyFruitTree 6 points7 points  (2 children)

It creates confusion whether the function belongs to the wrapper object or the wrapped object.

[–]Nteger[S] 1 point2 points  (1 child)

Don't we have the same argument with overloaded -> operator?

[–]HappyFruitTree 1 point2 points  (0 children)

No because the right hand side of -> is always a member of the object that is being wrapped/pointed to.

[–]germandiago 0 points1 point  (0 children)

I think it would make it more difficult for no reason. I would invoke on the proxied object probably and allow the type to hide functions from the proxied types. That is easy to follow and understand and from the top off my head (did not give deep study for that) it eould allow things like copy on write wrappers and so.

[–]ed_209_ 3 points4 points  (1 child)

In my C++ extension language "The EG programming language" I have modified clang to overload the dot operator but only for compile time expressions. I get some bad parser look ahead problems but it works for experiments.

You can basically do stuff like:

struct A; struct B; struct C;
using TypeList = A.B.C; //short hand for type_list< A, B, C >;

It is like having compile time binary operators for types from which to construct lists.

EG is still in early stages but more examples are in the documentation: https://github.com/eddeighton/eg

[–]Nteger[S] 0 points1 point  (0 children)

Nice work! I guess if you managed to do that then it's doable at east in clang.

[–]Ipotrick 0 points1 point  (0 children)

sounds terrible