Search code examples
c++c++11language-lawyerlvaluequalified-name

Qualified-ids, are they lvalues or prvalues?


I was trying to validate this statement (my emphasis) in paragraph §5.1.1/8 (page 87) of the C++11 Standard

A nested-name-specifier that denotes a class, optionally followed by the keyword template (14.2), and then followed by the name of a member of either that class (9.2) or one of its base classes (Clause 10), is a qualified-id; 3.4.3.1 describes name lookup for class members that appear in qualified-ids. The result is the member. The type of the result is the type of the member. The result is an lvalue if the member is a static member function or a data member and a prvalue otherwise.

with the following snippet:

#include <iostream>

namespace N {
    class A {
    public:
        int i;
        void f();
    };
}

int main()
{
    std::cout << &N::A::f << '\n';
    std::cout << &N::A::i << '\n';
}

clang and gcc compile this code and VS2013 requires the definition of the member function f.

All three of them print

1
1

but I have no idea where these numbers come from.

live example

According to the paragraph highlighted above the expressions N::A::f is a prvalue, as f is not a static member function. Nonetheless, I was able to take its address in the code.

At the same time, in §5.3.1/3 one reads (emphasis mine):

The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id. If the operand is a qualified-id naming a non-static member m of some class C with type T, the result has type “pointer to member of class C of type T” and is a prvalue designating C::m.

which gives the impression that neither N::A::f nor N::A::i are lvalues, as they are qualified-ids.


Solution

  • but I have no idea where these numbers come from.

    Pointer-to-members aren't pointers. No operator<< can output their original value, the best and only match is the one that outputs bool values. Thus they are converted to bool (which obviously yields true) and the output is 1. Try to insert std::boolalpha and check the output again.

    Nonetheless, I was able to take its address in the code.

    How is that a surprise to you? You quoted the part that allows and explains this exact construct. It clearly states that taking the adress of a qualified-id that names a non-static member designates that member.

    qualified-ids are not only lvalues or rvalues. It completely depends on context. If they designate non-static members from outside that members class or any subclass of it, they have to be prvalues as they don't designate any specific object but rather a value (or information, in other words -- the type and an offset).