"private" access specifier not respected in overloaded SFINAE context · Issue #107629 · llvm/llvm-project (original) (raw)
Given the following code (run it here), where "Base::Whatever" is private (both overloads), why does Clang correctly display false except when (both) "T" is "Derived" and function "Whatever" is overloaded. This appears to be erroneous behavior but it's a fuzzy area in this context (but see behavior table further below):
#include #include
class Base { private: // Defaults to this anyway but being explicit
void Whatever(int)
{
}
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.