10

I have the following test program:

#include <iostream>
#include <type_traits>
#include <utility>

template<typename Ty, std::size_t N>
void foo(Ty (&&)[N])
{
    std::cout << "Ty (&&)[" << N << "]\t" << std::is_const<Ty>::value << '\n';
}

template<typename Ty, std::size_t N>
void foo(Ty (&)[N])
{
    std::cout << "Ty (&)[" << N << "]\t" << std::is_const<Ty>::value << '\n';
}

template<typename Ty>
using id = Ty;

int main()
{
    std::cout.setf(std::cout.boolalpha);

    foo(id<int[]>{1, 2, 3, 4, 5});
    foo(id<int const[]>{1, 2, 3, 4, 5}); // <-- HERE.
    int xs[]{1, 2, 3, 4, 5};
    foo(xs);
    int const ys[]{1, 2, 3, 4, 5};
    foo(ys);
    foo(std::move(xs));
    foo(std::move(ys));
}

I would expect that the line marked with an arrow would call the rvalue overload like the non-const call just above it but it doesn't.

Is this just a bug in GCC or is there something in the standard that causes the lvalue overload to be selected?

Simple
  • 13,992
  • 2
  • 47
  • 47
  • Interesting, Clang gets this correct and calls the rvalue overload. – Xeo Jul 07 '13 at 02:49
  • Good question: my naive understanding of the standard agrees with yours. [Live](http://ideone.com/ErHuYO) if you want to see output. – Yakk - Adam Nevraumont Jul 07 '13 at 13:33
  • Something funny going on here: http://ideone.com/ptTJ8i -- my `const int` temporary is being treated like an `int&&`, not a `const int&&`. – Yakk - Adam Nevraumont Jul 07 '13 at 13:47
  • @Yakk there are no "const int temporaries". An rvalue of type "const int" does not exist, because const and volatile only make sense for objects. Rvalues of non-class/non-array types do not refer to objects, and hence the Standard says that for such rvalues, "const" and "volatile" is always absent. For the same reason, there are no "int temporaries": A temporary is an object whose lifetime soon stops. But an rvalue int such as "0" or "int()" does not refer to an object, and so there is no lifetime to stop. The spec hence doesn't say they're temporaries (but has a bug at one place that says). – Johannes Schaub - litb Jul 07 '13 at 14:31
  • @JohannesSchaub-litb: I don't get it. If "an rvalue of type `const int` does not exist", then what the heck is `const int&&`? – user541686 Jul 14 '13 at 08:26
  • @Mehrdad In the above comment, I have to correct one statement: There *are* prvalue const ints, but all of them are compiler-synthesized, during reference binding. In my opinion, these should be xvalues, because the purpose of the creation is to have an address/object to bind to. An `const int&&` can bind to xvalues of type `const int` or `int`. (What I said above was meant to only apply to prvalues, *not* about rvalues). – Johannes Schaub - litb Jul 14 '13 at 11:11
  • @JohannesSchaub-litb: I think you should delete the comment, I'm still wrapping my head around what the entire point of your comment is... it's more confusing than clarifying. – user541686 Jul 14 '13 at 11:20

1 Answers1

2

According to the standard §12.2 [class.temporary]:

Temporaries of class type are created in various contexts: binding a reference to a prvalue (8.5.3), returning a prvalue (6.6.3), a conversion that creates a prvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1), entering a handler (15.3), and in some initializations (8.5).

So id<int const[]>{1, 2, 3, 4, 5} is a temporary and therefore is an prvalue §3.10 [basic.lval]:

An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expression) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.

A prvalue (“pure” rvalue) is an rvalue that is not an xvalue.

Hence shall be selected overloaded function with rvalue reference argument.

Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
A. Mikhaylov
  • 228
  • 3
  • 6