Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to friend a specific template specialization?

Is there a syntax for friending only certain specializations of a templated class, or do you have to friend all specializations with the likes of:

template<class FooType> friend class Bar;

If it existed, I would be looking for something like:

template<class FooType> friend class Bar<FooType const>;

It seems the specializations have their own "friendable" identity, because they are not friends of each other by default. For instance, getFoo() here can't be called by the non-const case derived from the const specialization because it is private:

template<class FooType> class Bar;

template<class FooType>
class Bar<FooType const> {
public:
    Bar (std::string name) : _foo (name) { }
    FooType const * operator->() const
        { return &getFoo(); }
private:
    FooType const & getFoo() const
        { return _foo; }
private:
    FooType _foo;
};

template<class FooType>
class Bar : public Bar<FooType const> {
public:
    Bar (std::string name) : Bar<FooType const> (name) { }
    FooType * operator->()
        { return &getFoo(); }
private:
    FooType & getFoo()
        { return const_cast<FooType &>(Bar<FooType const>::getFoo()); }
};

You have to add template<class FooType> friend Bar; to the const specialization.

(As an aside, the tag description for friend is sort of funny.)

like image 760
HostileFork says dont trust SE Avatar asked Oct 23 '13 16:10

HostileFork says dont trust SE


1 Answers

You are looking for

friend Bar<FooType const>;

which is one of two ways in which friends can be declared. The first syntax declares a class a friend:

friend Type;

where Type can be a simple type Bar (which is not a template), or it can be a specific instantiation of a class template, for example Baz<int>. int can, of course, also be a template parameter from the enclosing class template or whatever you like. The point is: It's a single type that is given friend status.

The second syntax declares a class template to be a friend:

template< ... > friend class ClassTemplate;

where the ... is the template parameter declaration of ClassTemplate. As you can see, you have to specify just the template parameter list, but the list is not used anywhere. It is not possible to combine both syntaxes, there is no way to "partially friend" a class template or to use SFINAE/enable_if to enable or disable certain friend declarations. In fact it doesn't even make much sense to add names to the template parameters, in your above I'd just write

template< class > friend class Bar;

as adding FooType doesn't really add anything of value here.

like image 126
Daniel Frey Avatar answered Oct 11 '22 08:10

Daniel Frey