Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it ill-formed to attempt to access private member of a class to sfinae out overload?

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?

like image 382
W.F. Avatar asked Jan 14 '18 18:01

W.F.


1 Answers

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.

like image 169
Barry Avatar answered Oct 20 '22 16:10

Barry