尝试访问 class 的私有成员以 sfinae 过载是否格式错误?

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

在尝试创建特征以检查 class 字段是否公开可用时,我创建了一个代码:

#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);
}

但似乎编译失败 [gcc] ([clang] 似乎在这里更宽松)错误:

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

我挖掘了我的一些旧代码,做了类似的事情,归结为以下内容:

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);
}

看起来它在两个 [gcc] just as well as in [clang]. But when I was looking for a reason of gcc failure I found the 中都完成了它的工作,这表明每次尝试使用 class 的私有字段都是错误的,因此即使是第二个代码也应该避免.我是不是过度解读了这个问题,还是第二个代码真的是语言滥用?

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

这里实际上是 gcc 更宽松。 gcc bug 59002 是一个元错误,它捕获了 gcc 在访问控制和模板方面存在的许多错误。对于 gcc,在您的第一个场景中,访问 Foo::foo 没问题,即使它是私有的。在您的第二个稍微不同的场景中,gcc 正确地拒绝了私有访问。

does_not_have_foo 在第一个场景中正确实现,clang 正确编译它。只是 gcc 错误地实现了访问检查。第二种实现同样正确。