Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does MSVC compile this?

Both Clang and GCC refuse to compile this but MSVC doesn't.

class Foo {
    int name;
};

template <class T>
concept HasName = requires { T::name; };

static_assert(HasName<Foo>);

MSVC only checks if the name exists, but it doesn't enforce access restrictions (i.e., private), and allows member access from without a class instance/object.


Addition from comments below:
Making name public allows to code to compile. But name is a non-static member, so why it is allowed to refer to it as T::name inside the requires ?

like image 761
Zebrafish Avatar asked Oct 21 '25 21:10

Zebrafish


2 Answers

As already mentioned, MSVC is wrong to accept the code since name member is private.

However - you also seems to be interested (based on the comments) to know why making it public causes the code to be valid (and accepted by the major compilers - see demo).
Specifically since name is a non-static member why is it OK to use it as T::name in the requires expression.

The reason is that in an unevaluated context you can use this syntax to refer to non-static members.

This is mentioned in item 3 of the Usage section in this cppreference page:

  1. (for data members only, not member functions) When used in unevaluated operands.
    struct S
    {
       int m;
       static const std::size_t sz = sizeof m; // OK: m in unevaluated operand
    };
    
    std::size_t j = sizeof(S::m + 42); // OK: even though there is no "this" object for m
    

Notes: such uses are allowed via the resolution of CWG issue 613 in N2253, which is treated as a change in C++11 by some compilers (e.g. clang).

(emphasis is mine)

As you can see S::m is valid inside sizeof (even though m is non-static) because it is an unevaluated context, just like in your case.

like image 186
wohlstad Avatar answered Oct 23 '25 10:10

wohlstad


MSVC doesn't take into account name's access, which is an obvious bug in the compiler. Work it around by prepending an &:

class Foo {
    int name;
};

template <class T>
concept HasName = requires { &T::name; };

static_assert(HasName<Foo>);

This is rejected by all three compilers. And, all three accept it, if name's access is public.

like image 29
Dr. Gut Avatar answered Oct 23 '25 10:10

Dr. Gut



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!