8

Say I have two Template classes.

template<class T>
class baseclass1
{
    template<class> friend class baseclass2;
}

template<class D>
class baseclass2
{
     template<class T> void foo( D& x, T& y)
     {
          ...
     }
}

The Above code allows all types of baseclass1 to friend all types of baseclass2, a many-to-many relationship. I have two questions,

What is the syntax to allow baseclass1 to friend just the function

baseclass2<class D>::foo<class T>( D& x, T& y).  

And, what is the syntax to allow baseclass1 to friend just the function

baseclass2<class D>::foo<class T>( D& x, T& y) where T from baseclass1 matches The T from Function foo.

EDIT

To those who keep claiming you can't friend a template specialization. This code works

template<class cake>
class foo
{
    public:
        static void bar(cake x)
        {
            cout << x.x;
        }
};


class pie
{
    public:
        void set( int y){ x = y; }
    private:
        int x;

        friend void foo<pie>::bar(pie x);
};

class muffin
{
    public:
        void set( int y){ x = y; }
    private:
        int x;

    friend void foo<pie>::bar(pie x);
};

int main
{
        pie x;
        x.set(5);
        foo<pie>::bar(x);

        muffin y;
        y.set(5);
        //foo<muffin>::foo(y); //Causes a compilation Error because I only friended the pie specialization
}

Even notice where muffin friends the wrong foo, and still causes a compilation error. This works with both functions and classes. I am totally willing to accept that this isn't possible in my specific situation (It's actually looking more and more that way) I'd just like to understand why.

8bitwide
  • 2,071
  • 1
  • 17
  • 24
  • Do you need any `baseclass2::foo` to be a friend, or is `baseclass2` enough? – Kerrek SB Oct 30 '12 at 15:19
  • @Kerrek SB, the code in the example works well enough, The question is more academic than anything else, I was reading about and playing with the syntax for ever and could not for the life of me figure out how to restrict the friendship any further than the many-many shown above. – 8bitwide Oct 30 '12 at 15:32
  • 1
    Well, you can also have just a single friendship via `friend void baseclass2::template foo(T & , T &);`, or befriend all `foo`s in the fixed class `baseclass2` via `template friend void baseclass2::template foo(T &, U &);`. – Kerrek SB Oct 30 '12 at 15:43
  • @Kerrek: I think OP wants (for `baseclass1) `baseclass2::foo` to have access and `baseclass2::foo` to not have access (the latter would have access to `X`). Aka, the argument to `baseclass2` should be irrelevant to the friend status. – Xeo Oct 30 '12 at 15:51

2 Answers2

2

Befriending all possible specializations of baseclass2<D>::foo is rather easy:

template<class T> class baseclass1;

template<class D>
class baseclass2{
public:
  template<class T>
  void foo(D&, T&){ baseclass1<T> x; x.priv_foo(); }
};

template<class T>
class baseclass1{
  template<class D>
  template<class U>
  friend void baseclass2<D>::foo(D&, U&);

  void priv_foo(){}
};

template<class T>
class baseclass1{
  template<class D>
  template<class U>
  friend void baseclass2<D>::foo(D&, U&);
};

Live example.

A forward declaration of baseclass2 (so baseclass1 knows that baseclass2 exists and is a template) and two templates, one for the class, one for the function. It also looks like this for out-of-class definitions for function templates of class templates. :)

Befriending specifically baseclass2<D>::foo<T> is not possible, however, or I can't find the correct syntax for it.

A workaround might be some global function that forwards the access and together with the passkey pattern, but meh, it's a mess (imho):

template<class D> class baseclass2;

template<class D, class T>
void baseclass2_foo(baseclass2<D>& b, D&, T&);

template<class D, class T>
class baseclass2_foo_key{
  baseclass2_foo_key(){} // private ctor
  friend void baseclass2_foo<>(baseclass2<D>&, D&, T&);
};

template<class T>
class baseclass1{
public: // public access, but only baseclass2_foo can create the key
  template<class D>
  void priv_foo(baseclass2_foo_key<D, T> const&){}
};

template<class D, class T>
void baseclass2_foo(baseclass2<D>&, D&, T&){
  baseclass1<T> x;
  x.priv_foo(baseclass2_foo_key<D, T>());
}

template<class D>
class baseclass2{
public:
  template<class T>
  void foo(D& d, T& t){ baseclass2_foo(*this, d, t); }
};

Live example.

Community
  • 1
  • 1
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • Your first example doesn't seem to work. Did you notice that one of the parameters from foo is from the class template and not the function template?? – 8bitwide Oct 30 '12 at 15:38
  • @8bitwide: Yes, I did, as you can see in the example link. Note that I edited the answer to make the class names match and completely rewrote the second part. Now, how does The first example not work? – Xeo Oct 30 '12 at 15:40
  • The compiler returns Error 4 error C2998: 'Unique-Type-foo foo' : cannot be a template definition – 8bitwide Oct 30 '12 at 15:40
  • @8bitwide: I'm currently investigating whether that's a bug with MSVC (and Clang, since that rejects it too) or with GCC (since that allows it). However, I can vouch that the second solution compiles perfectly fine on all three (MSVC, Clang, GCC). – Xeo Oct 30 '12 at 16:06
  • If you remove the forward declaration and swap the order of the Classes, your first example works in msvc – 8bitwide Oct 30 '12 at 16:29
  • @8bitwide: You need a forward declaration of `baseclass1` then, it's MSVC's faulty two-phase lookup that allows the code without one. However, it's a good fix and I edited it into the answer. – Xeo Oct 30 '12 at 16:37
  • At this point you totally deserve the credit for a right answer, but see my edit above – 8bitwide Oct 30 '12 at 17:05
0

AFAIK you may specify all instantiation of foo as friend but not an specific instantiation:

template< class T >
class C1 {
public:
    template< class Q > void foo( T& x, Q& y ) {
    }
};
template< class T >
class C2 {
    template< class Y > 
    template< class Q > friend void C1<Y>::foo( Y&, Q& );
};
BigBoss
  • 6,904
  • 2
  • 23
  • 38
  • Check the one-one section of this web page. http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Ffriends_and_templates.htm It seems to suggest that exactly what I want is possible. – 8bitwide Oct 30 '12 at 15:46