Declaring set of member functions as friend by using template

孤者浪人 提交于 2019-12-23 11:32:05

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!