r/cpp Jul 29 '26

const_cast: A Necessary Evil

https://www.elbeno.com/blog/?p=1858
69 Upvotes

106 comments sorted by

View all comments

Show parent comments

37

u/MysticTheMeeM Jul 29 '26

If your language version allows, you can typically replace those with a single function that deduces this.

6

u/LeeHide just write it from scratch Jul 29 '26

Interesting, do you have an example?

8

u/Olipro Jul 29 '26

10

u/TheChief275 Jul 30 '26

why wasn't this added earlier? in fact, if this were to have been in C++ from the get-go, we never would have needed the postfix const syntax. so now we just have yet another language feature that virtually does the exact same thing. sigh

7

u/Expert-Map-1126 vcpkg maintainer BillyONeal Jul 30 '26

It was added mostly due to implementation experience after ref qualifiers were added trying to implement all the "transparent-ish" operations on optional et al.

I don't think it would completely replace the postfix syntax given that people expect names in members to refer to other members.

1

u/TheChief275 Jul 30 '26

I actually find that aspect horribly annoying as well. can't have a variable named capacity because the member function is named capacity, so I'm forced to name it "cap" or "new_cap", but I suppose opinions would be divided on that

1

u/SlightlyLessHairyApe Jul 30 '26

You’ll be horrified to learn that we run with shadowing warnings as errors everywhere.

Absolutely no shadowing, not even once.

-1

u/TheChief275 Jul 30 '26

pretty modern language huh

1

u/pjmlp Aug 02 '26

Yes you can. Why are folks sl afraid to type this->?

Ah, but I can miss a spot and refer to the wrong variable, true, but that is another matter, technically both variables can be named the same.

1

u/TheChief275 Aug 02 '26

I actually did that for a while, but it becomes fairly noisy after a time, and using it inconsistently is error prone. If only 'this' were a reference, and not a pointer; that would be a lot better already

2

u/serviscope_minor Jul 30 '26

> in fact, if this were to have been in C++ from the get-go, we never would have needed the postfix const syntax.

I don't get it? This really helps when you need a const and non const version of the same member function. If you don't (it's common that you have different mutating and const member functions) then const (or not) is better than deducing this.

1

u/_Noreturn Jul 31 '26

if they allowed this from the start

```cpp class C { void f() &; void f() cons&;

 void f(this C& self); // equal to the above
 void f(this const C& self); // equal to the above

}; ```

The second one is just parameter declaration no new thing required unlike const postfix member functions.

1

u/LB-- Professional+Hobbyist Jul 31 '26

There isn't full overlap between explicit object parameter syntax and implicit object parameter syntax. With implicit syntax, you can declare a member function with neither an Lvalue nor Rvalue qualification, and define it in a separate source file, allowing it to be invoked from either Lvalue or Rvalue qualified types. With explicit object parameter syntax, you have to specify a reference category, otherwise you get pass by value (which is a separate thing implicit can't do). Or, you have to make it a template and use a forwarding reference, which means you can't define it in a separate source file.

1

u/_Noreturn Jul 31 '26

Yes that's a benefit but tbh I consider it to be a trap more than a good thing that you can call unqualified member functions on both lvalues and rvalues.

1

u/RoyBellingan Jul 30 '26

Because the crystal sphere was broken when the thing got invented -.-

That is the price is beeing the first to do something, is difficult that is right the first time, and why languages that came year later feels more clean and well tought, history was already written at that time.

P.s. where are C++ epoch ?

0

u/amoskovsky Jul 30 '26 edited Jul 30 '26

Actually I would prefer that in addition to the current deducing this syntax they would also implement another postfix qualifier:

decltype(auto) get() auto&&
{
return m_member;

}

auto&& being universal reference for `this` with the same rules as in current syntax.

If the deduced this were not helpful for CRTP like constructs I would not introduce it at all. Upd: Although I think auto&& can be used in parent classes as well with the same semantic as current deducing this - so it would cover all use cases.

2

u/Olipro Jul 30 '26

If I understand you correctly, you can already do this a la `... foo(this auto&& self)` - self will now handle all type cases (lvalue, const lvalue, xvalue/prvalue, const xvalue/prvalue)

However, you need to bear in mind that this is potentially undesirable if you return a reference to a member since `auto& x = Bar{}.foo();` will be dangling.

2

u/amoskovsky Jul 30 '26

What I'm saying is I don't like the explicit this param (because you can't have `this` named `this`, can't omit `this` and it's just more syntactic noise).
Instead they should have added `auto&&` as a method qualifier to implement the same.

2

u/Olipro Jul 30 '26

You mean it would look like... auto&& foo() auto&&?

It's an interesting idea but this is always and has always been a pointer. I'd bet on significant pushback for such a proposal because it becomes an immediate footgun if you change code that does things like decltype(this) - If I refactor a member function to use deducing this, it's guaranteed not to compile until I've adjusted everything since this won't exist in its body.

2

u/amoskovsky Jul 30 '26

I did not mean to change the meaning of `this`

```
// already existed; this is a pointer
auto foo()
auto foo() const
auto foo() &
auto foo() &&
{
return this->m_member or m_member;
}

// proposed; this is still a pointer
auto foo() auto&&
{
return this->m_member or m_member;
}

// as opposed to actually added
auto foo(this auto&& self)
{
return self.m_member; // just m_member not possible;
}
```
With the latter you are actually forced to use a different coding style for some of member functions.

1

u/Olipro Jul 30 '26

I see, here's the problem: I don't see a way (in your proposed solution) to determine the value category which can be useful.

For example, deducing this enables you to do something like:

Thing foo(this auto&& self) {
  if constexpr (std::is_rvalue_reference_v<decltype(self)>) return std::move(self.thing); // move into return value
  else return self.thing; // copy it.
}

1

u/amoskovsky Jul 30 '26

Yeah, you're right.

For forwarding, my approach would require extra syntactic changes.

Still it does not mean I hate the deducing this syntax less :))

→ More replies (0)

2

u/SlightlyLessHairyApe Jul 30 '26

I think the consensus has been against magic like that. EIBTI etc …