问题
Given the following code:
class A;
struct B {
static void doIt(A* pa);
};
struct C {
static void doIt(A* pa);
};
class A {
int i = 9;
// below works but requires a line per each type
friend void B::doIt(A* pa);
friend void C::doIt(A* pa);
// the below however doesn't work
// template<typename T>
// friend void T::doIt(A* pa);
// (gcc error: member 'void T::doIt(A*)' declared as friend before type 'T' defined)
// (clang just ignores the above and the error is on accessing A::i in B and C)
};
void B::doIt(A* pa) {
cout << pa->i << endl;
}
void C::doIt(A* pa) {
cout << pa->i *2 << endl;
}
int main() {
A a;
B::doIt(&a);
C::doIt(&a);
}
Is it possible to replace the multiple friend
declarations to allow all void T::doIt(A* pa)
methods access the private members of A
?
Trying to instantiate B
and C
above A
doesn't help.
回答1:
Not exactly what do you asked but... if you templatize the B
, C
, etc. structs, you can get something similar.
#include <iostream>
class A;
template <std::size_t>
struct X
{ static void doIt(A* pa); };
class A
{
int i = 9;
template <std::size_t I>
friend void X<I>::doIt (A* pa);
};
template <>
void X<0U>::doIt(A* pa)
{ std::cout << pa->i << std::endl; }
template <>
void X<1U>::doIt(A* pa)
{ std::cout << pa->i * 2 << std::endl; }
template <>
void X<2U>::doIt(A* pa)
{ std::cout << pa->i * 3 << std::endl; }
using B = X<0U>;
using C = X<1U>;
using D = X<2U>;
int main() {
A a;
B::doIt(&a);
C::doIt(&a);
D::doIt(&a);
}
回答2:
I believe something similar to what you desire can be done using CRTP and private/protected virtual inheritance. The code below is only demonstration and definitely needs some work e.g. to not to involve template method friendship:
#include <iostream>
using namespace std;
class base {
protected:
int i = 9;
};
template <class F>
class crtp_base: virtual base { // private inheritance!
template <class T>
friend void F::doIt(T*);
};
template <class... AllF>
struct crtp_bases: crtp_base<AllF>... { };
struct B {
template <class T>
static void doIt(T* pa);
};
struct C {
template <class T>
static void doIt(T* pa);
};
class A: public crtp_bases<B, C> {
};
template <class T>
void B::doIt(T* pa) {
cout << pa->i << endl;
}
template <class T>
void C::doIt(T* pa) {
cout << pa->i * 2 << endl;
}
int main() {
A a;
B::doIt(&a);
//cout << a.i << endl; // error i is private member of 'base'
}
[live demo]
回答3:
I see no direct way, but one work-around could be declaring one class with several static methods (instead of several classes with one static method) and then declaring this class as friend, like:
...
struct D {
static void doItB(A* pa);
static void doItC(A* pa);
};
class A {
...
friend struct D;
...
};
void D::doItB(A* pa) {
cout << pa->i << endl;
}
...
D::doItB(&a);
D::doItC(&a);
...
来源:https://stackoverflow.com/questions/41924069/declaring-set-of-member-functions-as-friend-by-using-template