I've runned into some trouble trying to make friend declarations with sfinae checks (you can just jump into the code sample if you don't want explanations on "why" and "how").
Basically, I have some template class declaring two private member functions. Depending on the instantiation of the template type, I want to use either one or the other function.
So, if I don't want compilation to fail, the private function that I cannot use cannot be instantiated. So, I must called it through an sfinae check (an independent function). Considering it is private, I have to make my sfinae check a friend of my class.
However, I'm unable to do that, as the following (minimal) code illustrates. The things I don't want to change : the prototype of class A (f1 and f2 must remain private), the prototypes of class B1 and B2.
I understand why the stuff in comments fails (or I think I do), but I don't know how to fix it.
#include <iostream>
template<class T> class A;
template<class T>
auto sfinae_check(T& t, A<T>& a, int) -> decltype(t.b1(), void());
template<class T>
auto sfinae_check(T& t, A<T>& a, long) -> decltype(t.b2(), void());
template<class T>
class A
{
void f1() { t.b1(); }
void f2() { t.b2(); }
T& t;
//friend auto sfinae_check<>(T &t, A<T> &a, int);//obviously mismatches everything
//friend auto sfinae_check<>(T &t, A<T> &a, int) -> decltype(t.b1(), void()); //failure : no member named b1
//friend auto sfinae_check<>(T &t, A<T> &a, long) -> decltype(t.b2(), void()); //failure : no member named b2
public:
A(T& t) : t(t) {}
void f() { sfinae_check(t, *this, 0); }
};
template<class T>
auto sfinae_check(T& t, A<T>& a, int) -> decltype(t.b1(), void())
{
a.f1();
}
template<class T>
auto sfinae_check(T& t, A<T>& a, long) -> decltype(t.b2(), void())
{
a.f2();
}
struct B1
{
void b1() { std::cout << "b1" << std::endl; }
};
struct B2
{
void b2() { std::cout << "b2" << std::endl; }
};
int main()
{
B1 b1; B2 b2;
A<B1> a1(b1);
a1.f(); //should print b1
A<B2> a2(b2);
a2.f(); //should print b2
}