Example:
template<class T> class Base { public: Base(); friend class T; };
Now this doesn't work... Is there a way of doing this?
I'm actually trying to make a general class sealer like this:
class ClassSealer { private: friend class Sealed; ClassSealer() {} }; class Sealed : private virtual ClassSealer { // ... }; class FailsToDerive : public Sealed { // Cannot be instantiated };
I found this example on this site somewhere but I can't find it... (here)
I know there are other ways of doing this but just now I'm curious if you actually can do something like this.
class B{ template<class V> friend int j(); } template<class S> g(); template<class T> class A { friend int e(); friend int f(T); friend int g<T>(); template<class U> friend int h(); };
For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
It is explicitly disallowed in the standard, even if some versions of VisualStudio do allow it.
C++ Standard 7.1.5.3 Elaborated type specifiers, paragraph 2
3.4.4 describes how name lookup proceeds for the identifier in an elaborated-type-specifier. If the identifier resolves to a class-name or enum-name, the elaborated-type-specifier introduces it into the declaration the same way a simple-type-specifier introduces its type-name. If the identifier resolves to a typedef-name or a template type-parameter, the elaborated-type-specifier is ill-formed. [Note: this implies that, within a class template with a template type-parameter T, the declaration friend class T; is ill-formed. ]
I recognize the code above as a pattern to seal (disallow the extension of) a class. There is another solution, that does not really block the extension but that will flag unadvertidly extending from the class. As seen in ADOBE Source Library:
namespace adobe { namespace implementation { template <class T> class final { protected: final() {} }; }} #define ADOBE_FINAL( X ) private virtual adobe::implementation::final<T>
with the usage:
class Sealed : ADOBE_FINAL( Sealed ) {//... };
While it allows extension if you really force it:
class SealBreaker : public Sealed, ADOBE_FINAL( Sealed ) { public: SealBreaker() : adobe::implementation::final<Sealed>(), Sealed() {} };
It will restrict users from mistakenly do it.
EDIT:
The upcoming C++11 standard does allow you to befriend a type argument with a slightly different syntax:
template <typename T> class A { // friend class T; // still incorrect: elaborate type specifier friend T; // correct: simple specifier, note lack of "class" };
I found a simple trick to declare template parameters as friends:
template < typename T> struct type_wrapper { typedef T type; }; template < typename T> class foo { friend class type_wrapper < T>::type }; // type_wrapper< T>::type == T
However I do not know how this could help to define an alternative version of a class sealer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With