7

While attempting to create a trait to check whether the class field is publicly available I've created a code:

#include <type_traits>
#include <utility>

template <class T, class = void>
struct does_not_have_foo: std::true_type {};

template <class T>
struct does_not_have_foo<T, decltype(std::declval<T>().foo, void())>: std::false_type {};

class Foo {
    int foo;
};

int main() {
    static_assert(does_not_have_foo<Foo>::value);
}

But it appeared to failed to compile in [gcc] ([clang] seemed to be more permissive here) with an error:

prog.cc:8:56: error: 'int Foo::foo' is private within this context

I dug up for some older code of mine doing something similar which boils down to following:

template <class T>
auto does_not_have_foo(T t) -> decltype(t.foo, std::false_type()) {
    return {};
}

std::true_type does_not_have_foo(...) { return {}; }

class Foo {
    int foo;
};

int main() {
    static_assert(decltype(does_not_have_foo(Foo{}))::value);
}

It looked like it done its job in both [gcc] just as well as in [clang]. But when I was looking for a reason of gcc failure I found the question which suggests that every attempt to use of private field of the class is ill-formed and as such even the second code should be avoided. Am I over-interpreting the question or is the second code really the language abuse?

Barry
  • 286,269
  • 29
  • 621
  • 977
W.F.
  • 13,888
  • 2
  • 34
  • 81

1 Answers1

6

But it appeared to failed to compile in [gcc] ([clang] seemed to be more permissive here)

It's actually gcc that's more permissive here. gcc bug 59002 is a meta-bug that captures the many bugs that gcc has when it comes to access control and templates. To gcc, in your first scenario, accessing Foo::foo is fine, even though it's private. In your second, slightly different scenario, gcc correctly rejects the private access.

does_not_have_foo is correctly implemented in the first scenario, clang compiles it correctly. It's just that gcc incorrectly implements access checking. The second implementation is equally correct.

Barry
  • 286,269
  • 29
  • 621
  • 977