Search code examples
c++c++11language-lawyertypeid

typeid doesn't work with non-static member function


clang doesn't compile the third call to typeid below (see live example). But I can't see anything in §5.2.8 that disallows this, specially when we consider that the expression B::f is not a glvalue of polymorphic class type (see paragraph 3). Also, according to this paragraph the expression B::f is an unevaluated operand, and as such, the call typeid(B::f) should compile. Note that GCC doesn't compile any of the calls to typeid below:

#include <iostream>
#include <typeinfo>

struct A{ int i; };
struct B{ int i; void f(); };

int main()
{
    std::cout << typeid(A::i).name() << '\n';
    std::cout << typeid(B::i).name() << '\n';
    std::cout << typeid(B::f).name() << '\n';
}

Solution

  • As far as I can tell clang is correct, using a non static member is only valid in an unevaluated context if it is a data member. So it looks like gcc is incorrect for the first two cases, but gcc works correctly in the case of sizeof and decltype which also have unevaluated operands.

    From the draft C++11 standard section 5.1.1 [expr.prim.general]:

    An id-expression that denotes a non-static data member or non-static member function of a class can only be used:

    and includes the following bullet:

    if that id-expression denotes a non-static data member and it appears in an unevaluated operand. [ Example:

    struct S {
        int m;
    };
    int i = sizeof(S::m); // OK
    int j = sizeof(S::m + 42); // OK 
    

    —end example ]

    The rest of the bullets do not apply, they are as follows:

    • as part of a class member access (5.2.5) in which the object expression refers to the member’s class61 or a class derived from that class, or
    • to form a pointer to member (5.3.1), or
    • in a mem-initializer for a constructor for that class or for a class derived from that class (12.6.2), or
    • in a brace-or-equal-initializer for a non-static data member of that class or of a class derived from that class (12.6.2), or

    We know that operand is unevaluated from section 5.2.8 which says:

    When typeid is applied to an expression other than a glvalue of a polymorphic class type, [...] The expression is an unevaluated operand (Clause 5).

    We can see from the grammar that an id-expression is either an unqualified-id or a qualified-id:

    id-expression:
        unqualified-id
        qualified-id
    

    Update

    Filed a gcc bug report: typeid does not allow an id-expression that denotes a non-static data member.