A const std::reference_wrapper works similar to a reference, or a T* const (demo):
#include <functional>
struct S {
void operator()() { i++; }
int i = 0;
};
int main() {
S s;
const std::reference_wrapper<S> r = s;
// now s.i == 0
r();
// now s.i == 1
S* const p = &s;
// now s.i == 1
(*p)();
// now s.i == 2
}
r is const, and std::reference_wrapper::operator() is a const method, thus we can call it, which in turn modifies the pointee. But, this operator() is a standard library function, thus [res.on.data.races]#3 quoted from the C++23 standard applies to it:
A C++ standard library function shall not directly or indirectly modify objects ([intro.multithread]) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function's non-const arguments, including
this.
Does std::reference_wrapper violate this rule?
Problem is that std::reference_wrapper<S> does not store a value, but reference. std::reference_wrapper<S> is not changed, but S s; is changed.
It is like holding a constant pointer to modifiable object.
So everything is ok. r remains unchanged. s is updated.
So const version of function call operator is called and this member function call function call operator on s which is not const.
Documentation clearly states that operator() for is const
template< class... ArgTypes >
std::invoke_result_t<T&, ArgTypes...>
operator() ( ArgTypes&&... args ) const noexcept(/* see below */);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With