Can Sfinae Detect Private Access Violations

Can SFINAE detect private access violations?

Yes.

EDIT: C++11 Standard quote from §14.8.2 [temp.deduct]

8/ If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. [ Note: Access checking is done as part of the substitution process. —end note ]

This suggests to me that private can trigger an SFINAE error. Reading on:

Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation
of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed.—end note ]

The "immediate context" is not so clear to me... but it does not contradict my point :)

end of EDIT

So it seems to me that it will error out in an SFINAE way, this is further confirmed by this excerpt from Clang:

// clang/Basic/DiagnosticIDs.h:185-209

/// \brief Enumeration describing how the the emission of a diagnostic should
/// be treated when it occurs during C++ template argument deduction.
enum SFINAEResponse {
/// \brief The diagnostic should not be reported, but it should cause
/// template argument deduction to fail.
///
/// The vast majority of errors that occur during template argument
/// deduction fall into this category.
SFINAE_SubstitutionFailure,

/// \brief The diagnostic should be suppressed entirely.
///
/// Warnings generally fall into this category.
SFINAE_Suppress,

/// \brief The diagnostic should be reported.
///
/// The diagnostic should be reported. Various fatal errors (e.g.,
/// template instantiation depth exceeded) fall into this category.
SFINAE_Report,

/// \brief The diagnostic is an access-control diagnostic, which will be
/// substitution failures in some contexts and reported in others.
SFINAE_AccessControl
};

There are special cases with regard to Access Control in the case of SFINAE.

How to test access to a private function?

Answer from here

#include <iostream>

class Random1
{
public:
int random_function() { return 0; }
};

class Random2
{
private:
int random_function() { return 0; }
};

// SFINAE test
template <typename T>
class has_random_function
{
typedef char one;
typedef long two;

template <typename C> static one test( typeof(&C::random_function) ) ;
template <typename C> static two test(...);

public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

int main(int argc, char *argv[])
{
std::cout << "Random1: " << has_random_function<Random1>::value << std::endl;
std::cout << "Random2: " << has_random_function<Random2>::value << std::endl;
return 0;
}

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

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.

Private typedef and SFINAE in C++

K::type is not dependent on any template parameters, and therefore SFINAE does not apply.

If you instead use a dependent name, SFINAE will kick in, and the second overload of f would be selected. For example:

class K{
typedef void type;
};

template<typename T>
typename T::type f(T t) {}
void f(...) {}


int main() {
f(K());
}

Live Demo

detecting protected constructors of (possibly abstract) base class

This appears to work fine on my local GCC (4.7, courtesy of rubenvb). GCC on ideone prints several "implemented" compiler internal errors though.

I had to make the "implementation details" of the Experiment class public, because for some reasons (which smells like a bug), my version of GCC complains about them being private, even though only the class itself uses it.

#include <utility>

template<typename T, typename Ignored>
struct Ignore { typedef T type; };

struct EatAll {
template<typename ...T>
EatAll(T&&...) {}
};

template<typename T>
struct Experiment : T {
public:
typedef char yes[1];
typedef char no[2];

static void check1(T const&);
static void check1(EatAll);

// if this SFINAE fails, T accepts it
template<typename ...U>
static auto check(int, U&&...u)
-> typename Ignore<no&,
decltype(Experiment::check1({std::forward<U>(u)...}))>::type;

template<typename ...U>
static yes &check(long, U&&...);

public:
void f() {}
template<typename ...U,
typename std::enable_if<
std::is_same<decltype(Experiment::check(0, std::declval<U>()...)),
yes&>::value, int>::type = 0>
Experiment(U &&...u):T{ std::forward<U>(u)... }
{}
};

// TEST

struct AbstractBase {
protected:
AbstractBase(int, float);
virtual void f() = 0;
};

struct Annoyer { Annoyer(int); };

void x(Experiment<AbstractBase>);
void x(Annoyer);

int main() {
x({42});
x({42, 43.f});
}

Update: The code also works on Clang.



Related Topics



Leave a reply



Submit