https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116639
Bug ID: 116639 Summary: "private" access specifier not respected in overloaded SFINAE context Product: gcc Version: 14.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: admin at hexadigm dot com Target Milestone: --- Given the following code (run it at https://godbolt.org/z/cqv78Pdda), where "Base::Whatever" is private (both overloads), GCC (incorrectly) fails to compile when overloaded but correctly compiles when not overloaded (when you comment out the 2nd occurrence of "Whatever"). The other two compilers I tested both compile though Clang produces one wrong result when overloaded (I reported the issue to them as well). MSVC appears to be correct for all cases. See the behavior table further below (Clang first in the table since I reported it to them first). This appears to be erroneous behavior but it's a fuzzy area in this SFINAE context (but a bug seems likely). #include <type_traits> #include <iostream> class Base { private: // Defaults to this anyway but being explicit void Whatever(int) { } ///////////////////////////////////////////////// // Compilation erroneously fails but works when // commented out (so no longer overloaded) ///////////////////////////////////////////////// void Whatever(int, float) { } }; class Derived : public Base { }; template <typename T, typename U, typename = void> struct HasFuncWhatever : std::false_type { }; template <typename T, typename U> struct HasFuncWhatever<T, U, std::void_t<decltype(static_cast<U T::*>(&T::Whatever))> > : std::true_type { }; int main() { using T = Derived; using U = void (int); std::cout << std::boolalpha << HasFuncWhatever<T, U>::value; return 0; } Here's the behavior of the 3 compilers I tested (only MSVC presumably gets it right): T "Whatever" overloaded? Clang Displays MSVC Displays GCC Displays - ---------------------- -------------- ------------- ------------ Base No false (correct) false (correct) false (correct) Base Yes false (correct) false (correct) Fails compilation due to private access (incorrect) Derived No false (correct) false (correct) false (correct) Derived Yes true (incorrect) false (correct) Fails compilation due to private access (incorrect) Unless this is explicitly mentioned in the standard somewhere, or it's considered undefined behavior (implementation defined), the call to "&T::Whatever" in the partial specialization of "HasFuncWhatever" should always presumably fail since "Whatever" is private. The primary template should therefore always kick in so the code should always display false (and since GCC does in fact display false in the non-overloaded case but fails to compile when overloaded it appears to be broken behavior).