How can std::reference_wrapper<int> use operator+= if std::reference_wrapper doesn't have operator+=?

Viewed 72

Thank you all, I didn't even know about user-defined conversion function and how it works.


Why is it possible to use std::reference_wrapper<int>::operator+=, if such an operator does not exist, are there some implicit conversions?

#include <iostream>
#include <functional>
#include <boost/type_index.hpp>

using boost::typeindex::type_id_with_cvr;

template <typename C>
void test(C c)
{
    c += 1;
}

int main()
{
    int a = 3;
    test(a);
    std::cout << a << std::endl;
    test(std::ref(a));
    std::cout << a << std::endl;
}

Output:

3
4

To check that template works perfectly fine:

void test_2(std::reference_wrapper<int> c)
{
    c += 1;
}

int main()
{
    int a = 3;
    test_2(std::ref(a));
    std::cout << a << std::endl;
}

Output:

4

Still works as before. How is that possible?

Funny thing, that in auto d = b + c, d has an integer type.

int main()
{
    auto b = std::ref(a);
    auto c = std::ref(a);
    auto d = b + c;
    std::cout << type_id_with_cvr<decltype(d)>).pretty_name() << std::endl;
}

Output:

int
1 Answers

It's because it's implicitly convertible to a reference to T:

/* constexpr [c++20] */ operator T& () const noexcept;

In your case, it's implicitly convertible to an int&.


This ability to be implicitly convertible to an int& is also what would make it possible for you to define your function to take an int& while passing it a std::reference_wrapper<int>:

void test_2(int& c)       // <--+
{                         //    |
    c += 1;               //    |
}                         //    |
int main() {              //    |
    // ...                //    |
    test_2(std::ref(a));  // >--+
}
Related