Re: [boost] Sealed C++ class.

----Original Message---- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Sebastian Redl Sent: 07 April 2006 16:14 To: boost@lists.boost.org Subject: Re: [boost] Sealed C++ class.
Vladislav Lazarenko wrote:
template <typename T> class sealed : virtual private sealed_::sealed_impl<sealed, T>
Interesting idea. Any particular reason why this inheritance is virtual? sealed_impl being a template should be rare to duplicate as a base, and having no data members or virtual functions, it should be irrelevant even if it was duplicated. On the other hand, you introduce the troubles that come with virtual inheritance.
Sebastian Redl
If I write class Broken : public UniquePerson {}; Then the constructor of Broken has to invoke the constructor of sealed_impl. However the constructor is private, so it can't. The result is a compilation error. The problem is the code: template <typename T1, typename T2> class sealed_impl { friend typename T1; friend typename T2; ... 7.1.5.3 p2 says "[Note: this implies that, within a class template with a template type-parameter T, the declaration friend class T; is ill-formed.]" In other words, you can't do that :-( -- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB4 6WZ, ENGLAND Tel: +44 (0)1223 203894

Martin Bonner wrote:
----Original Message---- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Sebastian Redl Sent: 07 April 2006 16:14 To: boost@lists.boost.org Subject: Re: [boost] Sealed C++ class.
If I write class Broken : public UniquePerson {}; Then the constructor of Broken has to invoke the constructor of sealed_impl. However the constructor is private, so it can't. The result is a compilation error.
The problem is the code: template <typename T1, typename T2> class sealed_impl { friend typename T1; friend typename T2; ...
7.1.5.3 p2 says "[Note: this implies that, within a class template with a template type-parameter T, the declaration friend class T; is ill-formed.]"
In other words, you can't do that :-(
You are absolutely right. The only thing I am confused with is error description. The Boost is used not only by advanced developers, but by mid-level too. So when they will see such description it will be very difficult to find the real reason of error. Maybe I need just to put more comments in the header they will probably check.

Vladislav Lazarenko <snail@b2bits.com> writes:
Martin Bonner wrote:
The problem is the code: template <typename T1, typename T2> class sealed_impl { friend typename T1; friend typename T2; ...
7.1.5.3 p2 says "[Note: this implies that, within a class template with a template type-parameter T, the declaration friend class T; is ill-formed.]"
In other words, you can't do that :-(
You are absolutely right. The only thing I am confused with is error description. The Boost is used not only by advanced developers, but by mid-level too. So when they will see such description it will be very difficult to find the real reason of error. Maybe I need just to put more comments in the header they will probably check.
I proposed a similar thing on comp.std.c++ in 2001: http://groups.google.com/group/comp.std.c++/browse_thread/thread/accd1f3f57dfed60/c19fc42712e15296?lnk=st&q=comp.std.c%2B%2B+final+Anthony+Williams&rnum=1#c19fc42712e15296 Unfortunately the declaration "friend typename T", is not legal. It might happen to work on current releases of Microsoft compilers, but that's a bug in the compiler. Anthony -- Anthony Williams Software Developer Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk

On 4/7/06, Anthony Williams <anthony_w.geo@yahoo.com> wrote:
Vladislav Lazarenko <snail@b2bits.com> writes:
[snipped]
Unfortunately the declaration "friend typename T", is not legal. It might happen to work on current releases of Microsoft compilers, but that's a bug in the compiler.
Is friend typename identity<T>::type; also illegal?
Anthony -- Anthony Williams Software Developer Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
-- Felipe Magno de Almeida

Presumably, identity<T>::type would be a typedef which would also be invalid: Section 7.1.5.3 paragraph 2 of Standard C++: 3.4.4 describes how name lookup proceeds for the /identifier/ in an /elaborated-type-specifier/. ... 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. ] Tom. Felipe Magno de Almeida wrote:
On 4/7/06, Anthony Williams <anthony_w.geo@yahoo.com> wrote:
Vladislav Lazarenko <snail@b2bits.com> writes:
[snipped]
Unfortunately the declaration "friend typename T", is not legal. It might happen to work on current releases of Microsoft compilers, but that's a bug in the compiler.
Is
friend typename identity<T>::type;
also illegal?
Anthony -- Anthony Williams Software Developer Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
-- Felipe Magno de Almeida _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Martin Bonner" wrote:
The problem is the code: template <typename T1, typename T2> class sealed_impl { friend typename T1; friend typename T2; ...
7.1.5.3 p2 says "[Note: this implies that, within a class template with a template type-parameter T, the declaration friend class T; is ill-formed.]"
In other words, you can't do that :-(
While this and similar tricks are forbidden by Standard almost all current compilers are so "buggy" to support the feature. Comeau has even special switch to enable the feature. See article http://www.cuj.com/documents/s=8943/cujexp0312wilson2/ from Mathew Wilson for overview of these techniques. Generally, if something useful can be done because of widely present "bug" it is worth to consider. Boost.Typeof uses VC6 bug to implement otherwise impossible typeof there. /Pavel

On 4/8/06, Pavel Vozenilek <pavel_vozenilek@hotmail.com> wrote: [snip]
While this and similar tricks are forbidden by Standard almost all current compilers are so "buggy" to support the feature. Comeau has even special switch to enable the feature.
But is it worth becoming "existing practice"? As mentioned in boost web-page. [snipped]
Generally, if something useful can be done because of widely present "bug" it is worth to consider. Boost.Typeof uses VC6 bug to implement otherwise impossible typeof there.
It uses an emulation on compilers that dont support "native typeof". So that it can be used anyway. Now, if the compilers become less buggy, then we'll have to fix lots of code because it became an idiom relying on a bug-feature, since there isnt any workaround for a conforming compiler.
/Pavel
-- Felipe Magno de Almeida

Felipe Magno de Almeida wrote:
It uses an emulation on compilers that dont support "native typeof". So that it can be used anyway. Now, if the compilers become less buggy, then we'll have to fix lots of code because it became an idiom relying on a bug-feature, since there isnt any workaround for a conforming compiler.
I think when compilers will be less buggy as for this trick, the standard will describe template friends. Otherwise, why all compilers noted in article has the same bug? Anyway, I provided the other solution based on macros. It is not so pretty, but standard. I also remember that Mayers has some solution with pure virtual method, I will try to find out. Thank you for you interest and time taken to read discussion. -- Vladislav Lazarenko

Pavel Vozenilek wrote:
While this and similar tricks are forbidden by Standard almost all current compilers are so "buggy" to support the feature. Comeau has even special switch to enable the feature.
See article http://www.cuj.com/documents/s=8943/cujexp0312wilson2/ from Mathew Wilson for overview of these techniques.
Generally, if something useful can be done because of widely present "bug" it is worth to consider. Boost.Typeof uses VC6 bug to implement otherwise impossible typeof there.
/Pavel
AFAIK any tricks with typedefs are not legal in that context too. However, I am looking forward to solution that just works with all compilers boost support and the described technique will help us to support compilers that does not yet has so beautiful bug as template friends. I will prepare the version of "sealed" library taking that technique into account ASAP and we will take a look. As for standard solution, I found one, but it is not looking good, see below. Thank you for your interest. -- Vladislav Lazarenko // // Copyright (c) 2006 Vladislav Lazarenko <snail@b2bits.com> // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_SEALED_HPP #define BOOST_SEALED_HPP // MS compatible compilers support #pragma once. #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #define BOOST_DECLARE_SEALED(x) \ class boost_sealed_impl_##x { \ friend class x; \ private: \ boost_sealed_impl_##x() {} \ ~boost_sealed_impl_##x() {} \ }; \ #define BOOST_IMPLEMENT_SEALED(x) \ virtual private boost_sealed_impl_##x // Usage example: // // BOOST_DECLARE_SEALED(UniquePerson) // // class UniquePerson : BOOST_IMPLEMENT_SEALED(UniquePerson) // { // public: // UniquePerson() {} // ~UniquePerson() {} // }; // #endif

Dear colleagues, there is a version of sealed C++ class written with things described in article "http://www.cuj.com/documents/s=8943/cujexp0312wilson2/" by Matthew Wilson taken into account. Please review. Thank you in advance for you interest and time taken for review and discussion. Here is a template friends workaround for different compilers. Special thanks to Matthew Wilson. I decided to move it to the separated file because it can be reused many times. // // Copyright (c) 2006 Matthew Wilson <matthew@synesis.com.au> // Copyright (c) 2006 Vladislav Lazarenko <snail@b2bits.com> // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_TEMPLATE_FRIEND_HPP #define BOOST_TEMPLATE_FRIEND_HPP // MS compatible compilers support #pragma once. #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #if defined(__BORLANDC__) || \ defined(__COMO__) || \ defined(__DMC__) || \ (defined(__GNUC__) && __GNUC__ < 3) || \ defined(__INTEL_COMPILER) || \ defined(__WATCOMC__) || \ defined(_MSC_VER) # define BOOST_DECLARE_TEMPLATE_FRIEND(T) friend T #elif defined(__MWERKS__) # define BOOST_DECLARE_TEMPLATE_FRIEND(T) friend class T #elif defined(__GNUC__) && __GNUC__ >= 3 # define BOOST_DECLARE_TEMPLATE_FRIEND(T) \ namespace boost { namespace template_friend { \ struct friend_maker { \ typedef T T2; \ }; \ typedef typename friend_maker::T2 friend_type; \ friend friend_type; #endif #endif And here is sealed class template themselves. // // Copyright (c) 2006 Vladislav Lazarenko <snail@b2bits.com> // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_SEALED_HPP #define BOOST_SEALED_HPP // MS compatible compilers support #pragma once. #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include <boost/template_friend.hpp> namespace boost { // protection from unintended ADL namespace sealed_ { template <typename T1, typename T2> class sealed_impl { BOOST_DECLARE_TEMPLATE_FRIEND(T1); BOOST_DECLARE_TEMPLATE_FRIEND(T2); private: /* NOTE TO USER: Compile error from here indicates that you has specified sealed class as the base class of another class. The sealed classes is used to prevent derivation from a class. An error occurs if a sealed class is specified as the base class of another class. A sealed class cannot also be an abstract class. */ sealed_impl() {} ~sealed_impl() {} }; } /*! The sealed classes is used to prevent derivation from a class. An error occurs if a sealed class is specified as the base class of another class. A sealed class cannot also be an abstract class. */ template <typename T> class sealed : virtual private sealed_::sealed_impl<sealed, T> { public: //! Constructor. sealed() {} //! Destructor. ~sealed() {} }; /* Usage example: class UniquePerson : public boost::sealed<UniquePerson> // It is impossible to inherit UniquePerson class. { public: UniquePerson() {} ~UniquePerson() {} }; */ } #endif

Vladislav Lazarenko <snail@b2bits.com> writes:
# define BOOST_DECLARE_TEMPLATE_FRIEND(T) \ namespace boost { namespace template_friend { \ struct friend_maker { \ typedef T T2; \ }; \ typedef typename friend_maker::T2 friend_type; \ friend friend_type;
<snip> Okay, this macro opens new namespaces whereever I use it.
namespace boost { // protection from unintended ADL namespace sealed_ { template <typename T1, typename T2> class sealed_impl { BOOST_DECLARE_TEMPLATE_FRIEND(T1); BOOST_DECLARE_TEMPLATE_FRIEND(T2);
And here we are opening namespace within a class template body. Last time I checked that was illegal. What am I missing? -- Dave Abrahams Boost Consulting www.boost-consulting.com

Sorry, my fault. Unfortunately I don't have all compilers to test it. There are some troubles with the code I can just see: 1) No namespace should be used in BOOST_DECLARE_TEMPLATE_FRIEND. 2) friend_maker should be refactored to be unique name for each friend type. I will fix the code and upload to the Boost Vault, because, looks like, we started flame. Then people who are interested may pick it up and use. Thanks you for pointing me to errors. David Abrahams wrote:
Vladislav Lazarenko <snail@b2bits.com> writes:
# define BOOST_DECLARE_TEMPLATE_FRIEND(T) \ namespace boost { namespace template_friend { \ struct friend_maker { \ typedef T T2; \ }; \ typedef typename friend_maker::T2 friend_type; \ friend friend_type;
<snip>
Okay, this macro opens new namespaces whereever I use it.
namespace boost { // protection from unintended ADL namespace sealed_ { template <typename T1, typename T2> class sealed_impl { BOOST_DECLARE_TEMPLATE_FRIEND(T1); BOOST_DECLARE_TEMPLATE_FRIEND(T2);
And here we are opening namespace within a class template body. Last time I checked that was illegal.
What am I missing?

Martin Bonner wrote:
The problem is the code: template <typename T1, typename T2> class sealed_impl { friend typename T1; friend typename T2; ...
7.1.5.3 p2 says "[Note: this implies that, within a class template with a template type-parameter T, the declaration friend class T; is ill-formed.]"
In other words, you can't do that :-(
At least based on the C++-03 std. The current C++ draft does allow 'friend T1' so it depends how the 'boost' community would like to operate here. In general I think most implementers try to keep up with the working paper both to ensure that there isn't any problems with the proposed wording and also that they are in a position to ship when the new std appears. Personally, I also think it would be very useful if boost also tried some experimental features, as the unique way boost pushes compilers may also show problems in the standards wording this side of standardisation! Just a thought. Regards, Richard
participants (9)
-
Andy Little
-
Anthony Williams
-
David Abrahams
-
Felipe Magno de Almeida
-
Martin Bonner
-
Pavel Vozenilek
-
Richard Corden
-
Tom Honermann
-
Vladislav Lazarenko