Search code examples
c++rvalueoverload-resolution

Why is const temporary bound to rvalue reference parameter?


I have the following functions:

void func(void * const &ptr)
{
    std::cerr << "const" << std::endl;
}

void func(void *      &&ptr)
{
    std::cerr << "mutable" << std::endl;
}

void* const func2()
{
    return nullptr;
}

One overload takes const reference parameter and another takes mutable rvalue reference. And there is a function that returns const value.

When I pass that const temporary value to the function:

func(func2());

I expect the const overload to be chosen. But instead I get:

mutable

How is that possible? Why is const return value bound to non-const rvalue reference parameter?

This doesn't however happen when instead of void* I pass const struct to the function:

struct A
{
};

void func(A const &a)
{
    std::cerr << "const" << std::endl;
}

void func(A      &&a)
{
    std::cerr << "mutable" << std::endl;
}

A const func3()
{
    return A(); 
}

int main()
{
    func(func3());
    return 0;
}

The result is:

const

You can check this on coliru.

What is difference between const void* and const struct?

Is there a way to make overload that takes specifically const values?


Solution

  • Why is const temporary bound to rvalue reference parameter?

    Because it's not const by the time overload resolution happens.

    [expr.type]

    2 If a prvalue initially has the type “cv T”, where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis.

    A class type prvalue retains its cv-qualifications, but not a void* const prvalue. Overload resolution therefore happens with a plain void* prvalue, which explains the behavior you observe when the rvalue overload is chosen.

    The types this paragraph applies to are those "fundamental" types whose value is actually accessed by the program. So a prvalue of such a type is indeed a "pure", ephemeral value, and cannot be modified already.