Class container vs. the holy standard?
Hi, Triggered by Debian bug #362220 [0] I submitted GCC bug report #27178 [1] only to be told that container.h made use of a GCC extension that will have been removed from GCC in the upcoming 4.2.0 release [2]. Basically, where we were simply writing this: template <template <class> class> class container; typedef container<std::list> lst; we now have to write the more cumbersome: template <template <class, class> class> class container; typedef container<std::list> lst; This is because std::list has two template parameters, the element type and the allocator type. Ugh. It's ugly, because the intent was clearly to not bother the user with implementation details like the allocator. From the user's perspective, the intent is to express "container of T", never mind what type of container. I've attached a patch against CVS GiNaC-1.3 that converts all places flaged as errors in GCC 4.2 20060415 (experimental) to: template <template <class T, class = std::allocator<T> > class> class X; typedef X<std::list> lst; This is ugly as sin, because I don't think that we really wanted to express "STL-container of T", as the changed code now appears to imply. Any suggestions? -richy. [0] <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=362220> [1] <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27178> [2] <http://gcc.gnu.org/gcc-4.2/changes.html>, first bullet under C++ -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Triggered by Debian bug #362220 [0] I submitted GCC bug report #27178 [1] only to be told that container.h made use of a GCC extension that will have been removed from GCC in the upcoming 4.2.0 release [2]. Basically, where we were simply writing this:
template <template <class> class> class container; typedef container<std::list> lst;
we now have to write the more cumbersome:
template <template <class, class> class> class container; typedef container<std::list> lst;
This is because std::list has two template parameters, the element type and the allocator type. Ugh.
Hi, I saw the same problem coming in my own project, so I made some provisional changes in my own source to help. I don't know if my technique is directly applicable to your particular situation, but it might provide some ideas for a workaround. I wrote a forward declaration header for each class template definition in STL. Example: // \file "util/STL/allocator_fwd.h" ------------------------------------ namespace std { template <typename> class allocator; } // \file "util/STL/list_fwd.h" ----------------------------------------- #include "util/STL/allocator_fwd.h" namespace std { template <class T, class Alloc> class list; } namespace not_std { template <class T> struct default_list { typedef std::list<T, std::allocator<T> > type; }; } //---------------------------------------------------------------------- When I want to name the default std::list<T> type without without requiring its complete type, I can refer to default_list<T>::type, which has explicitly bound the trailing template arguments to their STL defaults. Advantage: avoids including <list> in certain headers where the complete type is not needed (e.g. return types, pointer/reference to... uses). And how does this relate to your container<T> ...
It's ugly, because the intent was clearly to not bother the user with implementation details like the allocator. From the user's perspective, the intent is to express "container of T", never mind what type of container. I've attached a patch against CVS GiNaC-1.3 that converts all places flaged as errors in GCC 4.2 20060415 (experimental) to:
template <template <class T, class = std::allocator<T> > class> class X; typedef X<std::list> lst;
The situation described above is a workaround to the lack of "template typedefs" in (present) std C++, which is our common underlying problem. A kludgy variation might use inheritance, but this doesn't result in equivalent types: namespace not_std { template <class T> class default_list : public std::list<T, std::allocator<T> > { typedef std::list<T, std::allocator<T> > type; }; } (This, however, does require std::list's complete definition.) You could then write something like this (using your example): template <template <class> class> class X; typedef X<not_std::default_list> lst; Again, not the greatest solution because of the inheritance relationship separating you from the actualy type you want. Rewriting your definitions to use a nested ::type member might only work for these non_std wrappers because the STL containers don't have self-referential 'type' member typedefs.
This is ugly as sin, because I don't think that we really wanted to express "STL-container of T", as the changed code now appears to imply.
Any suggestions?
I might see what other template metaprogramming techniques have to offer. I'm only a newbie in this subject, still learning on the fly. I would be very interested to hear what solution you end up using. David Fang
David Fang wrote:
I might see what other template metaprogramming techniques have to offer. I'm only a newbie in this subject, still learning on the fly. I would be very interested to hear what solution you end up using.
The problem is we can't have template <template <class, class> class C> class container besides template <template <class> class C> class container. But in this case, I think we can just name the former diffently, for example container_with_allocator. The attached patch is a quick shot: on first sight it's uglier that what has been suggested before (writing template <template< class T, class A = std::allocator<T>
class C> class container, but it doesn't turn all container types into container-assuming-STL types.
It has the problem that it still fails to link and on gcc-4.2 it even fails to compile with very strange error mesages from the assembler. But, heck, who cares!? -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
I wrote:
The problem is we can't have template <template <class, class> class C> class container besides template <template <class> class C> class container. But in this case, I think we can just name the former diffently, for example container_with_allocator. The attached patch is a quick shot: on first sight it's uglier that what has been suggested before (writing template <template< class T, class A = std::allocator<T> > class C> class container, but it doesn't turn all container types into container-assuming-STL types.
It has the problem that it still fails to link and on gcc-4.2 it even fails to compile with very strange error mesages from the assembler. But, heck, who cares!?
Okay, attached is a completed version of that patch. The link failures turned out to be due to some pieces still missing. And the assembler weirdness has gone away with a new snapshot of the compiler (dated 2006-05-06). I'm undecided: check that in or check in the other alternative that basically makes all containers std::allocator<ex> based? In any case, I don't think this is anything for the 1.3 branch since it changes the signature of everything containing a GiNaC::lst. Maybe toss a coin? -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Hi! On 2006-05-09, I wrote:
I'm undecided: check that in or check in the other alternative that basically makes all containers std::allocator<ex> based? In any case, I don't think this is anything for the 1.3 branch since it changes the signature of everything containing a GiNaC::lst. Maybe toss a coin?
GCC 4.2 is slowly drawing nearer, according to [0]. And with that release, compilation of GiNaC will fail. I would like to fix the problem in CVS, but I still have no strong feeling about which of the two proposed patches to apply. To recapitulate: The problem was the definition of template <template <class> class C> container where C is std::list<ex> or another STL container. But the container declaration doesn't account for the allocator template argument, which is in conflict with the standard. Patch 1 ([1a] or [1b]): Turn the template <template <class> class C> container into template <template <class T, class = std::allocator<T> > class C> container. Pro: Binary compatible (can be applied to 1.3-branch). Con: The intent is to express container of something and some allocator but rather container of something. Patch 2 ([2]): Add template <template <class, class> class C> container_with_allocator and use that for STL types. Pro: Expresses the original idea. Con: Not binary compatible (function signatures containing a lst& will differ) and may only be applied to HEAD. Some code duplication. There is another possiblity, very similar to Patch 2, but with the two types named differently: Patch 3): Change template <template <class> class C> container into template <template <class> class C> container_without_allocator and add a template <template <class, class> class C> container to be used with STL types. Pro: Binary compatible (can be applied to 1.3-branch). Con: Attaches a strange name to the "normal" case and a clear name to the special case. Same code duplication as in patch 2. Although it may appear confusing I am inclined to check in patch 3 to the 1.3-branch and patch 2 to HEAD. I'm going to do that within a few days unless somebody raises objections. This might be a good time for asking about the status of HEAD and the branch. Are there any projects pending? Jens, could you roll a release (whichever version) in the not so far future (including regenerated Bison files)? Regards -richy. [0] <http://gcc.gnu.org/ml/gcc/2006-07/msg00394.html> [1a] <http://www.ginac.de/pipermail/ginac-list/2006-April/000830.html> [1b] <http://www.ginac.de/pipermail/ginac-devel/2006-April/000932.html> [2] <http://www.ginac.de/pipermail/ginac-devel/2006-May/000959.html> -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Richard B. Kreckel wrote:
Patch 1 ([1a] or [1b]): Turn the template <template <class> class C> container into template <template <class T, class = std::allocator<T> > class C> container. Pro: Binary compatible (can be applied to 1.3-branch). Con: The intent is to express container of something and some allocator but rather container of something.
Typo: Con: The intent *isn't* to express container of something and some allocator but rather container of something. -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Hi, Richard B. Kreckel schrieb:
Patch 1 ([1a] or [1b]): Turn the template <template <class> class C> container into template <template <class T, class = std::allocator<T> > class C> container. Pro: Binary compatible (can be applied to 1.3-branch). Con: The intent is to express container of something and some allocator but rather container of something.
Patch 3): Change template <template <class> class C> container into template <template <class> class C> container_without_allocator and add a template <template <class, class> class C> container to be used with STL types. Pro: Binary compatible (can be applied to 1.3-branch). Con: Attaches a strange name to the "normal" case and a clear name to the special case. Same code duplication as in patch 2.
Why is patch 3 binary compatible? Doesn't the name container[_without_allocater] appear mangled in the ABI?
Although it may appear confusing I am inclined to check in patch 3 to the 1.3-branch and patch 2 to HEAD. I'm going to do that within a few days unless somebody raises objections.
Why do you think patch 3 is superior to patch 1? (Just) Consistent naming?
This might be a good time for asking about the status of HEAD and the branch. Are there any projects pending? Jens, could you roll a release (whichever version) in the not so far future (including regenerated Bison files)?
Anytime until Monday evening :-) And then again starting from one week later on. Any preference? Regards, Jens
Dear Jens, On Thu, 20 Jul 2006, Jens Vollinga wrote:
This might be a good time for asking about the status of HEAD and the branch. Are there any projects pending? Jens, could you roll a release (whichever version) in the not so far future (including regenerated Bison files)?
Anytime until Monday evening :-) And then again starting from one week later on. Any preference?
I have some patches pending that should go into HEAD before releasing 1.4. It is about improvements for automatic dummy index renaming. If a multiplication is constructed by mul::map(), GiNaC does not yet rename dummy indices. This changes some signatures in header files. Should be finished soon. I'm currently debugging. Best wishes, Chris
Dear Chris, Chris Dams schrieb:
This might be a good time for asking about the status of HEAD and the branch. Are there any projects pending? Jens, could you roll a release (whichever version) in the not so far future (including regenerated Bison files)? Anytime until Monday evening :-) And then again starting from one week later on. Any preference?
I have some patches pending that should go into HEAD before releasing 1.4. It is about improvements for automatic dummy index renaming. If a multiplication is constructed by mul::map(), GiNaC does not yet rename dummy indices. This changes some signatures in header files. Should be finished soon. I'm currently debugging.
I just thought and wrote (not clearly enough :-)) just about a 1.3.5 release. So, no need to hurry, yet. Regards, Jens
Hi! Jens Vollinga wrote:
Why is patch 3 binary compatible? Doesn't the name container[_without_allocater] appear mangled in the ABI?
The name container<T> does indeed appear in the symbols. However, there is no change to the functions that take a container<T> as one of the arguments, the type is the same. The name container_without_allocator<T> does not appear because it wouldn't be used in any of the existing functions (yet?). It may be surprising, but I've actually checked it: the set of text symbols provided by the library is not changed by either patch 1 or 3.
Although it may appear confusing I am inclined to check in patch 3 to the 1.3-branch and patch 2 to HEAD. I'm going to do that within a few days unless somebody raises objections.
Why do you think patch 3 is superior to patch 1? (Just) Consistent naming?
I think that patch 2 is superior to patch 1: <http://www.ginac.de/pipermail/ginac-devel/2006-April/000950.html>. Also, patch 2 is superior to patch 3. But patch 2 can only go into HEAD, not into the branch. I'm not so sure whether patch 3 is really superior to patch 1, but I thought that if patch 2 is going into HEAD, then patch 3 would be more appropiate for the branch because of reasons of symmetry. On another note: I'm just thinking that some of the code duplication can be avoided by deriving both classes from a common base basic_container that brings with it most of the implementation. Cheers -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Richard B. Kreckel wrote:
Although it may appear confusing I am inclined to check in patch 3 to the 1.3-branch and patch 2 to HEAD. I'm going to do that within a few days unless somebody raises objections.
Why do you think patch 3 is superior to patch 1? (Just) Consistent naming?
I think that patch 2 is superior to patch 1: <http://www.ginac.de/pipermail/ginac-devel/2006-April/000950.html>. Also, patch 2 is superior to patch 3. But patch 2 can only go into HEAD, not into the branch. I'm not so sure whether patch 3 is really superior to patch 1, but I thought that if patch 2 is going into HEAD, then patch 3 would be more appropiate for the branch because of reasons of symmetry.
Upon some more consideration, this appears to be rubbish, I'm afraid. I'm not going to change the semantics of the template container<> from release 1.3 to 1.4. So, patch 1 is going in to the 1.3-branch and a slimmed-down version of patch 2 is going in to HEAD RSN. Thank you for being skeptical. -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
On 2006-07-25, I wrote:
Although it may appear confusing I am inclined to check in patch 3 to the 1.3-branch and patch 2 to HEAD. I'm going to do that within a few days unless somebody raises objections.
Why do you think patch 3 is superior to patch 1? (Just) Consistent naming?
I think that patch 2 is superior to patch 1: <http://www.ginac.de/pipermail/ginac-devel/2006-April/000950.html>. Also, patch 2 is superior to patch 3. But patch 2 can only go into HEAD, not into the branch. I'm not so sure whether patch 3 is really superior to patch 1, but I thought that if patch 2 is going into HEAD, then patch 3 would be more appropiate for the branch because of reasons of symmetry.
Upon some more consideration, this appears to be rubbish, I'm afraid. I'm not going to change the semantics of the template container<> from release 1.3 to 1.4. So, patch 1 is going in to the 1.3-branch and a slimmed-down version of patch 2 is going in to HEAD RSN. Thank you for being skeptical.
Upon even more consideration, I started to be skeptical of the two-classes patch (container and container_with_allocator) for several reasons: 1) There's some interference between the two classes' names. 2) It's not even clear if the one without allocator is ever used. 3) It incurs more code to maintain. 4) If, at some time in the future, somebody needs a container<template <class> class>, it might well be that it can be solved with a revised C++0x. I've committed the simple patch on both the 1.3 branch and HEAD. Cheers -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
"Richard B. Kreckel" <kreckel@ginac.de> writes: | Hi, | | Triggered by Debian bug #362220 [0] I submitted GCC bug report #27178 | [1] only to be told that container.h made use of a GCC extension that | will have been removed from GCC in the upcoming 4.2.0 release [2]. That extension caused GCC to reject or silently change the semantics of well formed ISO C++ programs. The problem was noticed, it was decided to remove it as C++0x will also contain template aliases that make the extenion less relevant. GCC does not implement template alias yet. -- Gaby
participants (5)
-
Chris Dams
-
David Fang
-
Gabriel Dos Reis
-
Jens Vollinga
-
Richard B. Kreckel