Explicitly deleting the const &&
overload
A temporary object can have its lifetime extended by binding it to a const
lvalue reference (in a function call), whereas it cannot bind to a non-const
lvalue reference. This means that your original example implements the sought after behaviour (cannot be invoked with temporary objects), but at the cost of making the parameter non-const
(even though the implementation only queries and does not mutate the object). This arguably violates const
correctness.
As your free function API is inspecting an Object
object, you could consider changing it into a member function and use ref-qualifiers to explicitly delete the overload that will be chosen by overload resolution for temporary objects. A first approach could be to simply delete the &&
overload:
struct Object {
// ...
void foo() const & {}
void foo() && = delete;
};
int main() {
Object o = Object();
const Object co = Object();
o.foo();
co.foo();
//Object().foo(); // error: use of deleted function
}
However, this does not prohibit the, albeit somewhat contrived, case of const temporary objects as well as movable from const objects (const xvalues), as the deleted non-const
rvalue ref-qualifier overload is not viable for a const
rvalue argument:
std::move(co).foo(); // Accepted.
static_cast<const Object&&>(Object()).foo(); // Accepted.
Thus, instead of explicitly deleting the &&
overload, we can remove also the corner case by instead explicitly deleting the const &&
overload, as this will also be the overload of choice for non-const
temporary objects:
struct Object {
// ...
void foo() const & {}
void foo() const && = delete;
};
int main() {
Object o = Object();
const Object co = Object();
o.foo();
co.foo();
//std::move(o).foo(); // error: use of deleted function
//std::move(co).foo(); // error: use of deleted function
//Object().foo(); // error: use of deleted function
//static_cast<const volatile Object&&>(Object()).foo(); // error: use of deleted function
}
We may note that the same approach is used e.g. for the std::ref
and std::cref
helper functions of std::reference_wrapper
; from [functional.sym]:
// [refwrap], reference_wrapper
// ...
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
// ...
as you naturally want to delete a reference wrapper for temporary objects.
Object o = Object();
isObject o;
– Reitareiter