Little known feature of C++ is ref-qualifiers for member functions.
It works as I expect it to work in most cases, but it seems that std::optional
does not forward the knowledge of its imminent demise to contained object member functions.
For example consider the following code:
#include <chrono>
#include <iostream>
#include <optional>
struct Noisy {
Noisy(const std::string& data): data_(data){
}
~Noisy(){
std::cout << "Goodbye" << std::endl;
}
std::string data_;
const std::string& data() const & {
std::cout << "returning data by ref" << std::endl;
return data_;
}
std::string data() && {
std::cout << "returning data by move" << std::endl;
return std::move(data_);
}
};
int main() {
for (const auto chr: Noisy{"Heeeeeeeeeeeeeeeeello wooooorld"}.data()){
std::cout << chr;
}
std::cout << std::endl;
for (const auto chr: std::optional<Noisy>{"Heeeeeeeeeeeeeeeeello wooooorld"}->data()){
std::cout << chr;
}
std::cout << std::endl;
}
output is:
returning data by move
Goodbye
Heeeeeeeeeeeeeeeeello wooooorld
returning data by ref
Goodbye
(crash in clang with sanitizer or garbage(UB))
I was hoping that temporary std::optional
will be kind enough to call correct (data() &&
) function, but it seems it does not happen.
Is this a language limitation, or std::optional
just does not have correct machinery for this?
Full godbolt link.
note: my motivation is hacking around to see if I can be clever to enable safer usage of my classes in range based for loop, but realistically it is not worth the effort, this question is mostly about learning about language.
Overloaded operator arrow cannot do what you want; it terminates with a pointer always.
x->y
is defined by the standard as (*x).y
if and only if x
is a pointer; otherwise it is (x.operator->())->y
. This recursion only terminates if you hit a pointer.1
And there is no pointer to temporary type. Try this:
const auto chr: (*std::optional<Noisy>{"Heeeeeeeeeeeeeeeeello wooooorld"}).data()
Which does call the rvalue method. (via @largest_prime).
1 This recursion can also do Turing complete computation.