friend declaration of template specialized classes

1
2
3
4
5
6
7
class intClass{};
class stringClass{};

template <typename T>
class Mediator {
    // bunch of code
};

I want Mediator<int> to declare intClass friend, Mediator<std::string> to declare stringClass friend etc..., without having to redefine the entire specialization. How to do that? Something along the lines of
1
2
template<>
Mediator<int>::friend intClass;
Last edited on
Use a meta-function to identify the type-specific friend?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct A ;
struct B ;
struct C ;

template< typename T > struct mediator
{
    // ...

    private:
        // there is a second dummy template parameter with a default for the type
        // because complete specialisations are allowed only at namespace scope.
        template < typename, typename = void > struct friend_traits { struct type{}; };

        template < typename P > struct friend_traits<int,P> { using type = A ; }  ;
        template < typename P > struct friend_traits<std::string,P> { using type = B ; }  ;
        template < typename P > struct friend_traits<std::ostream,P> { using type = C ; }  ;

        friend typename friend_traits<T>::type ;
};
Good thinking there! Ok, I got it to work, but is there a way to default some types to void? Some specializations have just one friend, while some have many:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <typename EVENT>
class Mediator {
	template <typename, typename = void>
	struct friend_traits {
		struct type1{};  struct type2{};  struct type3{};  struct type4{};
		template <int N> struct type{};  // This idea didn't help
	};
        template <typename T> struct friend_traits<StaffCommand, T> {
		using type1 = Worker;  using type2 = Guard;  using type3 = Maid;  using type4 = Sultan;
	};
   	template <typename T> struct friend_traits<BattleCommand, T> {
		using type1 = Guard;  using type2 = void;  using type3 = void;  using type4 = void;  // too many voids!
	};
        template <typename T> struct friend_traits<MealCommand, T> {
		using type1 = Maid;  using type2 = Sultan;  using type3 = void;  using type4 = void;
	};
    friend typename friend_traits<EVENT>::type1;
    friend typename friend_traits<EVENT>::type2;
    friend typename friend_traits<EVENT>::type3;
    friend typename friend_traits<EVENT>::type4;
};
Last edited on
Ok, I think I've improved it a bit with the following, though I'm still not sure if it's the best way to go. It hardly looks any prettier (maybe even uglier), but at least there is no useless information being passed.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename EVENT>
class Mediator {
    template <typename, int, typename = void> struct friend_traits { struct type{}; };
    template <typename T> struct friend_traits<StaffCommand, 0, T> {using type = Worker;};
    template <typename T> struct friend_traits<StaffCommand, 1, T> {using type = Guard;};
    template <typename T> struct friend_traits<StaffCommand, 2, T> {using type = Maid;};
    template <typename T> struct friend_traits<StaffCommand, 3, T> {using type = Sultan;};
    template <typename T> struct friend_traits<BattleCommand, 0, T> {using type = Guard;};
    template <typename T> struct friend_traits<MealCommand, 1, T> {using type = Maid;};
    template <typename T> struct friend_traits<MealCommand, 0, T> {using type = Sultan;};
    friend typename friend_traits<EVENT, 0>::type;
    friend typename friend_traits<EVENT, 1>::type;
    friend typename friend_traits<EVENT, 2>::type;
    friend typename friend_traits<EVENT, 3>::type;
};


Oddly, Visual Studio 2013 allows me to compile it without the dummy variable T (i.e. complete specialization), but GCC disagrees so I will go with what both compilers agree on.
Last edited on
Trying to summing up
1
2
3
4
    friend typename friend_traits<EVENT, 0>::type;
    friend typename friend_traits<EVENT, 1>::type;
    friend typename friend_traits<EVENT, 2>::type;
    friend typename friend_traits<EVENT, 3>::type;

in one line, I've declared:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template <typename EVENT>
class Mediator {
    // ....
    template <int N> void establishFriendsForSpecialEVENTs();
};


template <typename EVENT>
template <int N> 
void Mediator<EVENT>::establishFriendsForSpecialEVENTs() {
	friend typename friend_traits<EVENT, N>::type;
	establishFriendsForSpecialEVENTs<N-1>();
}

template <typename EVENT>
template <>
void Mediator<EVENT>::establishFriendsForSpecialEVENTs<-1>() {}  // End of recursion. 

But the end-of-recursion definition won't compile for some reason.

EDIT: Though Visual Studio will allow it, GCC won't allow friend declaration outside of class.
Last edited on
> Though Visual Studio will allow it, GCC won't allow friend declaration outside of class.

Apply Visual Studio Updates (or use the compiler that comes with CTP Nov 2013)
http://rextester.com/IQFT48893
Topic archived. No new replies allowed.