4

I am having an issue with code failing to compile for an external library I am using. I believe that library compiles fine with gcc, but it fails to compile for me with clang.

I can recreate the issue as follows

template <class T>
class A {
public:
    struct B {
        int a;
    };

    void test();

private:
    T _t;
};

template <class T>
void A<T>::test()
{
    printf("Result %d", std::numeric_limits<decltype(B::a)>::max());
}

int main(int argc, char** argv)
{
    auto t = A<int>();
    t.test();
    return 0;
}

This fails to compile on clang with the following error

error: invalid use of non-static data member 'a' printf("Result %d", std::numeric_limits<decltype(B::a)>::max());

My questions are as follows:

  • What is the expected behavior?

  • decltype on non-static members was added in c++11. Does this apply to those declared in template classes?

  • Is this a compiler bug? Or an example of non-conformant code working with gcc?

Arnav Borborah
  • 11,357
  • 8
  • 43
  • 88
Alfie
  • 43
  • 5
  • 5
    @ArnavBorborah this is common misconception and it is not true. Only global scope names with leading underscore followed by lower case letter are reserved. – SergeyA Feb 20 '18 at 21:44
  • @SergeyA Ah, [you're right](https://stackoverflow.com/a/228797/6525260)! I guess you learn something new everyday! (But I still wouldn't use such names) – Arnav Borborah Feb 20 '18 at 21:45
  • 1
    @Arnav Borborah they are only reserved if followed by a second underscore (all names containing double underscore *anywhere* are reserved) or an upper-case letter. But, I agree, just avoidind names with leading underscore is a good idea in general (it's too easy to make a mistake). `_Foo` is reserved as is `__foo` and `foo__bar`, but `_foo` is not. – Jesper Juhl Feb 20 '18 at 21:46
  • @JesperJuhl too many people are used on naming private member variables with leading `_`. It is good to know it is allowed :D – SergeyA Feb 20 '18 at 21:56
  • I've been scorned for using `_variableName` within a class... I understand that it is reserved for global scope, but not as a class member! – Francis Cugler Feb 20 '18 at 22:28

1 Answers1

10

It was a bug in old version of Clang, and fixed in Clang 3.9.0: https://godbolt.org/g/zqFxL2

Normative Standarteese:

8.2.3: In some contexts, unevaluated operands appear ([expr.prim.req], [expr.typeid], [expr.sizeof], [expr.unary.noexcept], [dcl.type.simple], [temp]). An unevaluated operand is not evaluated. [ Note: In an unevaluated operand, a non-static class member may be named ([expr.prim]) and naming of objects or functions does not, by itself, require that a definition be provided ([basic.def.odr]). An unevaluated operand is considered a full-expression. — end note ]

SergeyA
  • 61,605
  • 5
  • 78
  • 137