0

Is this the canonical way to create a std::experimental::observer_ptr to a non-const object that cannot mutate the value it points to?

auto i = int{0};

auto p = std::experimental::make_observer(&std::as_const(i));
*p = 1; // compilation error, as desired

https://godbolt.org/z/h3Uq0o

EDIT:

What if the pointer already exists (which I suppose is the more common use-case)? Would we have to const_cast?

auto i = int{0};
auto p = &i;

auto q = std::experimental::make_observer(const_cast<const int*>(p));
*q = 1; // compilation error, as desired

https://godbolt.org/z/NbR6Nj

invexed
  • 645
  • 3
  • 10
  • In both of these cases, `i` is not a "const object". – Nicol Bolas Oct 05 '19 at 15:02
  • @NicolBolas Sure, but one can infer that I mean a pointer to an object that cannot mutate the value it points to. – invexed Oct 05 '19 at 15:09
  • @NicolBolas I've edited the original question for clarity. – invexed Oct 05 '19 at 15:13
  • 1
    This might be a case for NOT using `auto` and `make_observer`, but just writing out `std::experimental::observer_ptr p`. – aschepler Oct 05 '19 at 15:18
  • Does C++ even have canonical ways of doing things? Since operator & can be overloaded sometimes you may also need to write something like `auto p{ ::std::experimental::make_observer(::std::addressof(::std::as_const(i)))};` – user7860670 Oct 05 '19 at 15:21
  • @VTT Builtin operators cannot be overloaded. `&` on an `int` means what it means. – L. F. Oct 06 '19 at 11:44

1 Answers1

-1

Don't complicate matters. Just do

observer_ptr<const int> p{&i};

And everything is fine.

You can also do this according to the spec:

observer_ptr p{&std::as_const(i)};

but GCC and Clang seems to diverge from the spec here. The implementation uses a qualified name for the (element_type*) constructor, therefore blocking class template argument deduction.


Much like std::make_pair, make_observer exists because the library fundamentals 2 TS is created in pre-C++17 era. Class template argument deduction wasn't a thing at that time. Nowadays, we rarely need a separate make function like std::make_pair (counterexample: reference wrappers, see Usefulness of std::make_pair and std::make_tuple in C++1z), and similarly we rarely need make_observer.

Therefore, it doesn't make much sense to talk about the "canonical" way of using a pre-C++17 feature like observer_ptr in C++17. Granted, we can use class template argument deduction if it actually works. That's simply not even considered in the design of observer_ptr.

L. F.
  • 19,445
  • 8
  • 48
  • 82
  • Not using CTAD with the smart pointer construction helpers in the STL (```std::make_unique``` and ```std::make_shared```) is a hard habit to break and was the source of the confusion in this case. You're right that there is no need for a helper when constructing a 'dumb' smart pointer like ```std::observer_ptr```. – invexed Oct 06 '19 at 09:43
  • I'll happily accept your answer if you highlight the difference between ```std::observer_ptr``` and the existing smart pointers as it pertains to CTAD and the ```std::make_``` helpers. – invexed Oct 06 '19 at 09:47
  • @invexed I don’t think this has much to do with smart / dumb pointers whatsoever. The reason that the smart pointers disable CTAD is there is no good way of differentiating pointers obtained from new and new[] and also make_shared can allocate once. `observer_ptr` is based on C++14, so it doesn’t make much sense to talk about CTAD on it I suppose? – L. F. Oct 06 '19 at 10:07
  • There is still a difference between ```observer_ptr``` and the other smart pointers in that you can use CTAD with the former but can't with the latter (which led to my question in the first place). I will accept your answer though; people can read these comments if need be. Thanks. – invexed Oct 06 '19 at 11:00
  • @invexed `observer_ptr` isn't in the standard, so it isn't updated for C++17 ... – L. F. Oct 06 '19 at 11:43
  • I thought your answer was showing CTAD: ```observer_ptr p{&std::as_const(i)};```, but I've just tested it and indeed, CTAD doesn't work with ```observer_ptr```. Perhaps you should edit your answer so that it doesn't look like the template argument is being deduced? – invexed Oct 06 '19 at 12:02
  • @invexed I said, "GCC seems to diverge from the spec here. The implementation uses a qualified name for the `(element_type*)` constructor, therefore blocking class template argument deduction." – L. F. Oct 06 '19 at 12:05
  • I am using Clang, not GCC; ```observer_ptr``` is not CTAD-enabled with Clang either. For that reason, I think ```make_observer``` is a perfectly reasonable way of creating an ```observer_ptr``` if you don't need to explicitly specify whether or not the pointer can modify the value it points to. – invexed Oct 06 '19 at 12:07
  • @invexed OK, seems the source in libstdc++ and libc++ are the same. – L. F. Oct 06 '19 at 12:09