6

When using std::weak_ptr, it is best practice to access the corresponding std::shared_ptr with the lock() method, as so:

std::weak_ptr<std::string> w;
std::shared_ptr<std::string> s = std::make_shared<std::string>("test");

w = s;

if (auto p = w.lock())
   std::cout << *p << "\n";
else
   std::cout << "Empty";

If I wanted to use the ternary operator to short hand this, it would seem that this:

std::cout << (auto p = w.lock()) ? *p : "Empty";

would be valid code, but this does not compile.

Is it possible to use this approach with the ternary operator?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Hufh294
  • 89
  • 5
  • 1
    All parts of a conditional expression are in turn expressions. You can't have definition of variables in expressions. – Some programmer dude Oct 01 '21 at 22:44
  • 2
    Somewhat related: [what's an expression and expression statement in c++?](https://stackoverflow.com/q/7479946/11082165) and [Expression Versus Statement](https://stackoverflow.com/q/19132/11082165). Declarations are not expressions in C++, so it won't be possible to declare `p` inside of the first expression of `?:`. However, _assignments_ are expressions, so something like `(p = w.lock()) ? *p : "Empty"` would be valid, assuming `p` was already declared. – Brian61354270 Oct 01 '21 at 22:49
  • 1
    You could declare `p` outside the ternary and then assign it inside, but then you can't use the placeholder `auto`. It'd be `std::shared_ptr p; std::cout << (p = w.lock()) ? *p : "Empty";` – Nate Eldredge Oct 01 '21 at 23:34
  • @NateEldredge you might not be able to use `auto` in that case, but you can still deduce the `shared_ptr` type from the `weak_ptr`, by using `std::shared_ptr p;`, or even simpler `decltype(w.lock()) p;` – Remy Lebeau Oct 02 '21 at 15:21

2 Answers2

4

auto p = w.lock() is not an assignment. It's a declaration of a variable. You can declare a variable in the condition of an if statement, but you cannot declare variables within a conditional expression.

You can write:

auto p = w.lock();
std::cout << (
    p ? *p
      : "Empty"
);
eerorika
  • 232,697
  • 12
  • 197
  • 326
2

If you want to introduce a variable for an expression (like let in Lisp or Haskell), you can use a lambda:

std::cout << [p = w.lock()] {return p ? *p : "Empty";}();

This also confines the ?:, which interprets std::cout as part of the condition in your question.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76