Here's a status report on the indexing_v2 work I've been doing: o I've improved the handling for containers of shared_ptr's, so that sorting and searching automatically do the right indirection. o Fixed various layout and naming convention issues o container_proxy is now strongly exception safe (commit or rollback) o The container_proxy Generator parameter now works even on MSVC6 o I've added a Flags parameter to allow expensive features (in terms of object code size) to be selectively disabled. o I've added convenience templates for use without partial template specialization support (vector_suite, map_suite, etc.) These last two points bring the interface a little closer to what Joel de Guzman had originally, although the flags that he used were passed separately as individual bool parameters instead of as flag bits. He certainly wasn't kidding about the extra effort in supporting MSVC6. So as far as I know, there is no outstanding coding work remaining for the current level of functionality. I'm now updating the documentation to reflect the recent changes, and then the suite, in my opinion, will be ready for release. One possible extension I've been thinking about, as suggested by Ralf W. Grosse-Kunstleve, is the idea of allowing construction of a container from a Python iterable object: e.g. v = Vector ([1,2,3]) The ideal way to do it would be to massage the single input parameter into two C++ iterators that could be passed to the templated vector constructor, but I haven't looked far enough into the constructor dispatching internals to know how to do this, or even if it is possible. The problem, AFAICS, would be knowing when to select that overload of the constructor and when not to, and how/where to insert the necessary code to create the two iterators from the single Python object. Any advice would be appreciated. This might also be significant for another of Ralf's suggestions - pickling support. So I have two loosely related questions - what do people thing about including the current indexing_v2 suite in release 1.31, and should I try adding the iterator-based constructor support? -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
So I have two loosely related questions - what do people thing about including the current indexing_v2 suite in release 1.31,
2 questions: a. Where can I browse the documentation? b. Where can I review the test code?
and should I try adding the iterator-based constructor support?
IMO yes, but my opinion isn't strongly-held. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
So I have two loosely related questions - what do people thing about including the current indexing_v2 suite in release 1.31,
2 questions:
a. Where can I browse the documentation?
b. Where can I review the test code?
Both are available on the indexing_v2 branch in libs/python, so you could just do an update -r indexing_v2 in that directory. The docco is then in libs/python/doc/v2/containers.html and the test code is in files like test_<container>_*.cpp and .py in libs/python/test/ Alternatively, the html-only portion of the documentation is available at: http://cvs.sourceforge.net/viewcvs.py/*checkout*/boost/boost/libs/python/doc... I'm still working on some updates to this.
and should I try adding the iterator-based constructor support?
IMO yes, but my opinion isn't strongly-held.
I guess the real question is how to do it. I'll start looking into it a bit deeper, but I suspect I'll need some advice. Converting the Python iterable object to two C++ iterators isn't hard, but I don't know how to create the forwarding function and a sensible __iter__ overload that gets called (only) when appropriate. The problem is that there will be other container constructors that really do take just a single parameter, so how can the code decide whether to try one of them or whether to try making two C++ iterators out of the parameter. For one thing, it would be good if the code could use the normal copy constructor if passed a wrapped C++ object of the same type, or at least use C++ iterators directly rather than going through a C++ wrapper of a Python iterator that is actually a C++ iterator (C++ -> Python -> C++ dispatching). I don't know how realistic that idea is. -- Raoul Gough. export LESS='-X'
--- Raoul Gough <RaoulGough@yahoo.co.uk> wrote:
and should I try adding the iterator-based constructor support?
IMO yes, but my opinion isn't strongly-held.
I think it is really important.
I guess the real question is how to do it. I'll start looking into it a bit deeper, but I suspect I'll need some advice. Converting the Python iterable object to two C++ iterators isn't hard, but I don't know how to create the forwarding function and a sensible __iter__ overload that gets called (only) when appropriate. The problem is that there will be other container constructors that really do take just a single parameter, so how can the code decide whether to try one of them or whether to try making two C++ iterators out of the parameter.
For one thing, it would be good if the code could use the normal copy constructor if passed a wrapped C++ object of the same type, or at least use C++ iterators directly rather than going through a C++ wrapper of a Python iterator that is actually a C++ iterator (C++ -> Python -> C++ dispatching). I don't know how realistic that idea is.
This sounds overly complicated to me. I believe you could get the job done in relatively little time if you started with the container conversions header from the scitbx: http://cvs.sourceforge.net/viewcvs.py/cctbx/scitbx/include/scitbx/boost_python/container_conversions.h?rev=1.10&view=auto Put the code in another namespace, remove to_tuple and the tuple_mapping* convenience templates. Instantiate from_python_sequence<> when a vector-style container is wrapped. Also automatically wrap the copy constructor of that vector-style container. My meta-programming is not very advanced. Therefore I dare suggesting that the from_python_sequence<> template and the copy consturctor should only be instantiated if the user supplies one of the policies (call them FromPythonSequencePolicies). Don't get side-tracked by performance considerations. If someone constructs a container from Python slow performance is expected. What counts for the Python programmer is convenience and flexibility. If you make it easy to wrap C++ containers users can quickly implement time-critical functions in C++. Ralf __________________________________ Do you Yahoo!? Free Pop-Up Blocker - Get it now http://companion.yahoo.com/
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
So I have two loosely related questions - what do people thing about including the current indexing_v2 suite in release 1.31,
2 questions:
a. Where can I browse the documentation?
b. Where can I review the test code?
Both are available on the indexing_v2 branch in libs/python, so you could just do an update -r indexing_v2 in that directory. The docco is then in libs/python/doc/v2/containers.html and the test code is in files like test_<container>_*.cpp and .py in libs/python/test/
Alternatively, the html-only portion of the documentation is available at:
http://cvs.sourceforge.net/viewcvs.py/*checkout*/boost/boost/libs/python/doc...
"Safety" is missing from the design goals. Was that not one of the goals? I was under the impression that this: Note: the suite hasn't yet been tested on a compiler without partial template specialization support. If you have any results with such a compiler (good or bad) please report them on the mailing list for the Python C++-SIG. is no longer true. Wrong? I don't like the use of abbrevs. like "algo_...." I'm concerned that iterator_range may duplicate functionality somewhere else in Boost. An iterator_range class has recently been discussed on the main list as part of a library review. Overall, after just a quick look, I'm impressed, though I don't think the documentation gives a clear picture of how to use all this stuff yet. I wouldn't be reeady to approve it until I can read some more complete docs, so that I can understand the whole enchilada. Internal policies detail The container_suite object typically adds more than one function to the Python class, and not all of those functions can, or should, use exactly the same policies. For instance, the Python len method, if provided, should always return its result by value. The library actually uses up to three different sets of policies derived from the one provided to the with_policies function. These are: The supplied policies, unchanged The supplied precall policy only, using default_call_policies for result conversion. The supplied precall policies, and the supplied result conversion policies applied to each element of a returned list You just drop any postcall component of supplied policies? Rationale? The "Extending and customizing" section isn't understandable, since you haven't even introduced the components you're discussing at that point. Is it important to make reference to def_visitor, or is that merely an implementation detail? If the latter, it should be dropped as a distraction. 2] Note that Algorithms and ContainerTraits don't represent individual templates in the diagram, but groups of related templates. For instance, there are actually templates called list_algorithms and assoc_algorithms, among others. Don't you mean that they represent concepts? "lessthan_comparable" should be "less_than_comparable". Why "visitor_helper", and not operator()? There's no description of what visitor_helper is for. has_copyable_iter can be determined by looking at iterator_traits<I>::iterator_category (or better, iterator_traversal<I>::type). The user shouldn't supply it. I don't understand is_reorderable. How is that different from is_convertible< iterator_traits<C::iterator>::iterator_category , forward_iterator_tag
::value && is_non_const_lvalue_iterator<C::iterator>::value && is_assignable<C::value_type>::value
?? I realize we don't have is_assignable, but shouldn't you phrase this in terms of something fundamental like value_type assignability? We can ask all the other questions (see boost/iterator/is_lvalue_iterator.hpp). Once you tell the suite that "has_find" don't you also need to tell it how (i.e. via member function or otherwise)? The use of static constants in ContainerTraits is unattractive to me, because it's not particularly extensible. What about asking the user to provide an mpl::set of the property type tags: typedef mpl::set<mutable,find,insert,push_back> capabilities; or something? You actually have the name "value_traits_" in a table. Intended? ^ Why would you ask the user to supply the Container's size_type and iterator instead of deducing them from the container itself? I am a bit concerned about how reference documentation for various components and headers is grouped all into one file, containers.html. I don't believe the precedent set by the pickling support in this regard was a good one. We have a semi-coherent [;-)] reference manual organization - why should there be any supported public headers missing from it? IMO it would be better (though not a showstopper) if containers.html were just narrative/tutorial, with pointers to the hard-core reference material. I'd also like to hear if Joel has any concerns. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes: [snip] "Safety" is missing from the design goals. Was that not one of the goals?
Well that's a tough one. For instance, using return_by_reference when returning a value held in a container is pretty dangerous (consider deletions or vector reallocations). On the other hand, I wouldn't like to rule it out as an option merely on that basis. Certainly the container_proxy component does backflips to try and prevent any dangers, so perhaps this needs some mention of safety? All it says at the moment is this: Provide an emulation of Python reference semantics for /values/ in vector-like containers.
I was under the impression that this:
Note: the suite hasn't yet been tested on a compiler without partial template specialization support. If you have any results with such a compiler (good or bad) please report them on the mailing list for the Python C++-SIG.
is no longer true. Wrong?
Yes, this is out of date.
I don't like the use of abbrevs. like "algo_...."
You mean algo_selector? I can rename this to algorithm_selector if you'd prefer, I don't mind either way.
I'm concerned that iterator_range may duplicate functionality somewhere else in Boost. An iterator_range class has recently been discussed on the main list as part of a library review.
OK - I'll keep an eye out for this and replace it when/if boost gets its own implementation.
Overall, after just a quick look, I'm impressed, though I don't think the documentation gives a clear picture of how to use all this stuff yet. I wouldn't be reeady to approve it until I can read some more complete docs, so that I can understand the whole enchilada.
Internal policies detail
The container_suite object typically adds more than one function to the Python class, and not all of those functions can, or should, use exactly the same policies. For instance, the Python len method, if provided, should always return its result by value. The library actually uses up to three different sets of policies derived from the one provided to the with_policies function. These are:
The supplied policies, unchanged
The supplied precall policy only, using default_call_policies for result conversion.
The supplied precall policies, and the supplied result conversion policies applied to each element of a returned list
You just drop any postcall component of supplied policies? Rationale?
The supplied postcall currently gets dropped completely for functions that return integers or void (e.g. __len__ and sort) on the assumption that it is only intended for use when returning container elements. For instance, you don't want to use return_internal_reference on the result of a call to container.size(). I'm not entirely happy with this aspect myself, particularly as it relates to the absent pop() method which would always need some kind of by-value policy. I've thought of a clean solution, which would be to require a CallPolicies "package" that contains typedefs and factory functions for various different CallPolicies that the suite requires. For example len_policies, element_policies, pop_policies or maybe a slightly different level of granularity.
The "Extending and customizing" section isn't understandable, since you haven't even introduced the components you're discussing at that point.
Is it important to make reference to def_visitor, or is that merely an implementation detail? If the latter, it should be dropped as a distraction.
OK.
2] Note that Algorithms and ContainerTraits don't represent individual templates in the diagram, but groups of related templates. For instance, there are actually templates called list_algorithms and assoc_algorithms, among others.
Don't you mean that they represent concepts?
Well that seems to be the Boost term for it. I'd be happier using it if you could point me to a definition of the term, so I can embed a hyperlink to the definition. I don't think everyone who uses the Python or indexing suite documentation will be familiar with it otherwise (I know I wasn't initially).
"lessthan_comparable" should be "less_than_comparable".
OK.
Why "visitor_helper", and not operator()?
Static function.
There's no description of what visitor_helper is for.
By gum, you're right. Well spotted.
has_copyable_iter can be determined by looking at iterator_traits<I>::iterator_category (or better, iterator_traversal<I>::type). The user shouldn't supply it.
I guess this needs some explanation in the documentation - there is an iterator_traits template that deduces many properties automatically (for instance, has_copyable_iter is indeed determined by iterator category). I'll add some documentation for the case that client code wants to use the template as a base class, although there is certainly no necessity for it to do so.
I don't understand is_reorderable. How is that different from
is_convertible< iterator_traits<C::iterator>::iterator_category , forward_iterator_tag
::value && is_non_const_lvalue_iterator<C::iterator>::value && is_assignable<C::value_type>::value
??
I realize we don't have is_assignable, but shouldn't you phrase this in terms of something fundamental like value_type assignability? We can ask all the other questions (see boost/iterator/is_lvalue_iterator.hpp).
The iterator traits template I mentioned above just uses is_mutable_ref<std_traits::reference> (with an obvious is_mutable_ref implementation). This actually deduces the wrong answer for std::map and even std::set with some standard libraries, so I ended up overriding it manually in set_traits and map_traits.
Once you tell the suite that "has_find" don't you also need to tell it how (i.e. via member function or otherwise)?
Yes indeed. The ContainerTraits and Algorithms have to work together on this - you can't have "has_find" true and then not provide an implementation of find, count and maybe index in your Algorithms. I suppose I should really document the exact requirements. Also, I've recently added two static member functions to the ValueTraits concept for the less_than and equal_to comparisons. This is where the automatic shared_ptr handling happens. It's not documented yet.
The use of static constants in ContainerTraits is unattractive to me, because it's not particularly extensible. What about asking the user to provide an mpl::set of the property type tags:
typedef mpl::set<mutable,find,insert,push_back> capabilities;
or something?
Looks like a good idea. I'll give this a go.
You actually have the name "value_traits_" in a table. Intended? ^
There is a template called value_traits, so the ContainerTraits member type is called value_traits_ (underscore at end). A bit lame I guess.
Why would you ask the user to supply the Container's size_type and iterator instead of deducing them from the container itself?
The client could use one of the existing ContainerTraits templates as a base class and avoid the need for defining this explicitly (needs documenting, as noted above). On the other hand, it is also possible to interface the suite with a container that doesn't provide anything like an STL-style interface, by completely replacing the traits and algorithms templates.
I am a bit concerned about how reference documentation for various components and headers is grouped all into one file, containers.html. I don't believe the precedent set by the pickling support in this regard was a good one. We have a semi-coherent [;-)] reference manual organization - why should there be any supported public headers missing from it? IMO it would be better (though not a showstopper) if containers.html were just narrative/tutorial, with pointers to the hard-core reference material.
Yes, I think this is inevitable, given the weaknesses you've identified. I guess I was trying to economize on documentation effort, but I suppose it needs to be more rigorous.
I'd also like to hear if Joel has any concerns.
Me too. Thanks for your comments so far - I'll work on them as part of the current updates I'm doing. -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes: [snip] "Safety" is missing from the design goals. Was that not one of the goals?
Well that's a tough one. For instance, using return_by_reference when returning a value held in a container is pretty dangerous (consider deletions or vector reallocations).
There are supposed to be proxies which just store an index and do range checks. Is that what container_proxy is?
On the other hand, I wouldn't like to rule it out as an option merely on that basis. Certainly the container_proxy component does backflips to try and prevent any dangers, so perhaps this needs some mention of safety?
Yes. If that's the safe one, it should be the default, and safety was a major goal of Joel's original work.
All it says at the moment is this:
Provide an emulation of Python reference semantics for /values/ in vector-like containers.
I was under the impression that this:
Note: the suite hasn't yet been tested on a compiler without partial template specialization support. If you have any results with such a compiler (good or bad) please report them on the mailing list for the Python C++-SIG.
is no longer true. Wrong?
Yes, this is out of date.
I don't like the use of abbrevs. like "algo_...."
You mean algo_selector? I can rename this to algorithm_selector if you'd prefer, I don't mind either way.
I prefer.
Overall, after just a quick look, I'm impressed, though I don't think the documentation gives a clear picture of how to use all this stuff yet. I wouldn't be reeady to approve it until I can read some more complete docs, so that I can understand the whole enchilada.
Internal policies detail
The container_suite object typically adds more than one function to the Python class, and not all of those functions can, or should, use exactly the same policies. For instance, the Python len method, if provided, should always return its result by value. The library actually uses up to three different sets of policies derived from the one provided to the with_policies function. These are:
The supplied policies, unchanged
The supplied precall policy only, using default_call_policies for result conversion.
The supplied precall policies, and the supplied result conversion policies applied to each element of a returned list
You just drop any postcall component of supplied policies? Rationale?
The supplied postcall currently gets dropped completely for functions that return integers or void (e.g. __len__ and sort) on the assumption that it is only intended for use when returning container elements. For instance, you don't want to use return_internal_reference on the result of a call to container.size().
You need to document the postcall behaviors and the rationale.
2] Note that Algorithms and ContainerTraits don't represent individual templates in the diagram, but groups of related templates. For instance, there are actually templates called list_algorithms and assoc_algorithms, among others.
Don't you mean that they represent concepts?
Well that seems to be the Boost term for it.
Not Boost: standard C++, STL, Generic Programming, CUJ, etc. all use this term.
I'd be happier using it if you could point me to a definition of the term, so I can embed a hyperlink to the definition.
http://www.boost.org/more/generic_programming.html#concept
I don't think everyone who uses the Python or indexing suite documentation will be familiar with it otherwise (I know I wasn't initially).
"lessthan_comparable" should be "less_than_comparable".
OK.
Why "visitor_helper", and not operator()?
Static function.
OK. The name sounds like it exposes implementation details. It should describe what it's for.
has_copyable_iter can be determined by looking at iterator_traits<I>::iterator_category (or better, iterator_traversal<I>::type). The user shouldn't supply it.
I guess this needs some explanation in the documentation - there is an iterator_traits template that deduces many properties automatically
Traits globs like std::iterator_traits are a bad idea; it's much better to define individual metafunctions.
(for instance, has_copyable_iter is indeed determined by iterator category). I'll add some documentation for the case that client code wants to use the template as a base class, although there is certainly no necessity for it to do so.
I don't understand why you would even give the user the option to supply information that you can correctly deduce ??
I don't understand is_reorderable. How is that different from
is_convertible< iterator_traits<C::iterator>::iterator_category , forward_iterator_tag
::value && is_non_const_lvalue_iterator<C::iterator>::value && is_assignable<C::value_type>::value
??
I realize we don't have is_assignable, but shouldn't you phrase this in terms of something fundamental like value_type assignability? We can ask all the other questions (see boost/iterator/is_lvalue_iterator.hpp).
The iterator traits template I mentioned above just uses is_mutable_ref<std_traits::reference>
Not a good idea; the standard doesn't place any requirements on the reference type of most iterators.
(with an obvious is_mutable_ref implementation). This actually deduces the wrong answer for std::map and even std::set with some standard libraries, so I ended up overriding it manually in set_traits and map_traits.
That's why I'm suggesting using the formula above.
Once you tell the suite that "has_find" don't you also need to tell it how (i.e. via member function or otherwise)?
Yes indeed. The ContainerTraits and Algorithms have to work together on this - you can't have "has_find" true and then not provide an implementation of find, count and maybe index in your Algorithms. I suppose I should really document the exact requirements.
Uh, I suppose ;-)
Also, I've recently added two static member functions to the ValueTraits concept for the less_than and equal_to comparisons. This is where the automatic shared_ptr handling happens. It's not documented yet.
That means little to me as I don't understand the system yet.
The use of static constants in ContainerTraits is unattractive to me, because it's not particularly extensible. What about asking the user to provide an mpl::set of the property type tags:
typedef mpl::set<mutable,find,insert,push_back> capabilities;
or something?
Looks like a good idea. I'll give this a go.
We may need to whip mpl::set into shape. In the meantime you could use an mpl::vector, and mpl::find which will give slightly longer compiles but should work.
You actually have the name "value_traits_" in a table. Intended? ^
There is a template called value_traits, so the ContainerTraits member type is called value_traits_ (underscore at end). A bit lame I guess.
Yeah, I think we should revisit these decisions.
Why would you ask the user to supply the Container's size_type and iterator instead of deducing them from the container itself?
The client could use one of the existing ContainerTraits templates as a base class and avoid the need for defining this explicitly (needs documenting, as noted above). On the other hand, it is also possible to interface the suite with a container that doesn't provide anything like an STL-style interface, by completely replacing the traits and algorithms templates.
The normal way to deal with that is to supply a metafunction: template <class C> struct container_value_type { typedef typename C::value_type type; }; And then have the user specialize it for other types. A slightly better implementation would look like: template <class has = mpl::false_, class C> struct container_value_type_impl { }; template <class C> struct container_value_type_impl<mpl::true_, C> { typedef typename C::value_type type; }; template <class C> struct container_value_type : container_value_type_impl<has_value_type<C>::type, C> { }; On second thought, I guess I can understand why you want to give the user the ability to package the mapping into container-hood and hand it to you. This reminds me of the kind of explicit concept mapping you can do in Haskell. My feeling is that if you want to go this way, the user should be supplying a traits *generator*, not the traits themselves.
I am a bit concerned about how reference documentation for various components and headers is grouped all into one file, containers.html. I don't believe the precedent set by the pickling support in this regard was a good one. We have a semi-coherent [;-)] reference manual organization - why should there be any supported public headers missing from it? IMO it would be better (though not a showstopper) if containers.html were just narrative/tutorial, with pointers to the hard-core reference material.
Yes, I think this is inevitable, given the weaknesses you've identified. I guess I was trying to economize on documentation effort,
I can understand the desire ;-)
but I suppose it needs to be more rigorous.
Unfortunately, yes. If I can't understand it, it won't survive well in the BPL codebase.
I'd also like to hear if Joel has any concerns.
Me too. Thanks for your comments so far - I'll work on them as part of the current updates I'm doing.
My feeling at the moment is that this work is going to be great, but that it probably won't be ready (or I won't be comfortable with it) in time for 1.31.0. We can still try, but I'm going to be busy...
-- Raoul Gough.
export LESS='-X'
I read the help on less -X, but I don't understand why I'd want this? -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes: [snip] "Safety" is missing from the design goals. Was that not one of the goals?
Well that's a tough one. For instance, using return_by_reference when returning a value held in a container is pretty dangerous (consider deletions or vector reallocations).
There are supposed to be proxies which just store an index and do range checks. Is that what container_proxy is?
The container_proxy is a container wrapper, and it returns element proxies that do the range checking - they cooperate on tracking element movement due to inserts/deletes. However, container_proxy is completely optional and only works with vector-like containers anyway (e.g. deque works, list doesn't).
On the other hand, I wouldn't like to rule it out as an option merely on that basis. Certainly the container_proxy component does backflips to try and prevent any dangers, so perhaps this needs some mention of safety?
Yes. If that's the safe one, it should be the default, and safety was a major goal of Joel's original work.
I don't think it can be the default, since it isn't embedded in the suite. It provides an interface which is compatible with the indexing suite, but is also designed to be reasonably convenient to use directly in C++. This is important, since there might be C++ code that modifies the container while Python code still holds proxies pointing into it. This was one of the issues I raised early on with the previous version of the suite, since the proxying was actually hidden from the C++ code. As I said then, the ideal solution is to use a container of shared pointers anyway - if that's not possible, exposing a container_proxy wrapper of the container is an option for vector-like containers. [snip]
I don't like the use of abbrevs. like "algo_...."
You mean algo_selector? I can rename this to algorithm_selector if you'd prefer, I don't mind either way.
I prefer.
OK - will change this. [snip]
The supplied postcall currently gets dropped completely for functions that return integers or void (e.g. __len__ and sort) on the assumption that it is only intended for use when returning container elements. For instance, you don't want to use return_internal_reference on the result of a call to container.size().
You need to document the postcall behaviors and the rationale.
OK.
2] Note that Algorithms and ContainerTraits don't represent individual templates in the diagram, but groups of related templates. For instance, there are actually templates called list_algorithms and assoc_algorithms, among others.
Don't you mean that they represent concepts?
Well that seems to be the Boost term for it.
Not Boost: standard C++, STL, Generic Programming, CUJ, etc. all use this term.
I'd be happier using it if you could point me to a definition of the term, so I can embed a hyperlink to the definition.
Thanks for this - I wish I'd seen that when I first started reading the Python docs. By the way, I'm pretty sure the C++ standard never uses the word "Concept" in this context. It refers to "requirements" like "LessThanComparable" or "Assignable", which is more or less the same thing but with a different name.
I don't think everyone who uses the Python or indexing suite documentation will be familiar with it otherwise (I know I wasn't initially).
"lessthan_comparable" should be "less_than_comparable".
OK.
Why "visitor_helper", and not operator()?
Static function.
OK. The name sounds like it exposes implementation details. It should describe what it's for.
I couldn't think of anything better at the time. It's just a hook to let the algorithms, container traits or value traits do any additional set up during the def() call for the whole suite. Maybe def_hook?
has_copyable_iter can be determined by looking at iterator_traits<I>::iterator_category (or better, iterator_traversal<I>::type). The user shouldn't supply it.
I guess this needs some explanation in the documentation - there is an iterator_traits template that deduces many properties automatically
Traits globs like std::iterator_traits are a bad idea; it's much better to define individual metafunctions.
(for instance, has_copyable_iter is indeed determined by iterator category). I'll add some documentation for the case that client code wants to use the template as a base class, although there is certainly no necessity for it to do so.
I don't understand why you would even give the user the option to supply information that you can correctly deduce ??
... can correctly deduce /for STL-like containers/.
I don't understand is_reorderable. How is that different from
is_convertible< iterator_traits<C::iterator>::iterator_category , forward_iterator_tag
::value && is_non_const_lvalue_iterator<C::iterator>::value && is_assignable<C::value_type>::value
??
I realize we don't have is_assignable, but shouldn't you phrase this in terms of something fundamental like value_type assignability? We can ask all the other questions (see boost/iterator/is_lvalue_iterator.hpp).
The iterator traits template I mentioned above just uses is_mutable_ref<std_traits::reference>
Not a good idea; the standard doesn't place any requirements on the reference type of most iterators.
That probably explains the troubles. I'll look into using the value_type instead.
(with an obvious is_mutable_ref implementation). This actually deduces the wrong answer for std::map and even std::set with some standard libraries, so I ended up overriding it manually in set_traits and map_traits.
That's why I'm suggesting using the formula above.
Once you tell the suite that "has_find" don't you also need to tell it how (i.e. via member function or otherwise)?
Yes indeed. The ContainerTraits and Algorithms have to work together on this - you can't have "has_find" true and then not provide an implementation of find, count and maybe index in your Algorithms. I suppose I should really document the exact requirements.
Uh, I suppose ;-)
Also, I've recently added two static member functions to the ValueTraits concept for the less_than and equal_to comparisons. This is where the automatic shared_ptr handling happens. It's not documented yet.
That means little to me as I don't understand the system yet.
The use of static constants in ContainerTraits is unattractive to me, because it's not particularly extensible. What about asking the user to provide an mpl::set of the property type tags:
typedef mpl::set<mutable,find,insert,push_back> capabilities;
or something?
Looks like a good idea. I'll give this a go.
We may need to whip mpl::set into shape. In the meantime you could use an mpl::vector, and mpl::find which will give slightly longer compiles but should work.
It should ideally support by-value element removal, so set is the right abstraction. Are you suggesting that it isn't fully functional?
You actually have the name "value_traits_" in a table. Intended? ^
There is a template called value_traits, so the ContainerTraits member type is called value_traits_ (underscore at end). A bit lame I guess.
Yeah, I think we should revisit these decisions.
Why would you ask the user to supply the Container's size_type and iterator instead of deducing them from the container itself?
The client could use one of the existing ContainerTraits templates as a base class and avoid the need for defining this explicitly (needs documenting, as noted above). On the other hand, it is also possible to interface the suite with a container that doesn't provide anything like an STL-style interface, by completely replacing the traits and algorithms templates.
The normal way to deal with that is to supply a metafunction:
template <class C> struct container_value_type { typedef typename C::value_type type; };
And then have the user specialize it for other types. A slightly better implementation would look like:
template <class has = mpl::false_, class C> struct container_value_type_impl { };
template <class C> struct container_value_type_impl<mpl::true_, C> { typedef typename C::value_type type; };
template <class C> struct container_value_type : container_value_type_impl<has_value_type<C>::type, C> { };
On second thought, I guess I can understand why you want to give the user the ability to package the mapping into container-hood and hand it to you. This reminds me of the kind of explicit concept mapping you can do in Haskell.
Yes, I don't see how doing it via specializations for each individual property would make things more convenient for the client code. I guess I'll document the available base classes that perform the automatic deductions when I provide separate HTML files for each header. This makes it more or less trivial for STL-like containers, without actually requiring it.
My feeling is that if you want to go this way, the user should be supplying a traits *generator*, not the traits themselves.
I am a bit concerned about how reference documentation for various components and headers is grouped all into one file, containers.html. I don't believe the precedent set by the pickling support in this regard was a good one. We have a semi-coherent [;-)] reference manual organization - why should there be any supported public headers missing from it? IMO it would be better (though not a showstopper) if containers.html were just narrative/tutorial, with pointers to the hard-core reference material.
Yes, I think this is inevitable, given the weaknesses you've identified. I guess I was trying to economize on documentation effort,
I can understand the desire ;-)
but I suppose it needs to be more rigorous.
Unfortunately, yes. If I can't understand it, it won't survive well in the BPL codebase.
Makes sense.
I'd also like to hear if Joel has any concerns.
Me too. Thanks for your comments so far - I'll work on them as part of the current updates I'm doing.
My feeling at the moment is that this work is going to be great, but that it probably won't be ready (or I won't be comfortable with it) in time for 1.31.0. We can still try, but I'm going to be busy...
OK - there's a fair bit here to chew on.
export LESS='-X'
I read the help on less -X, but I don't understand why I'd want this?
Here's the answer: Disables sending the termcap initialization and deinitialization strings to the terminal. This is sometimes desirable if the deinitialization string does something unnecessary, like clear- ing the screen. every GNU-based system I've ever worked on clears the screen by default on exit from less. Annoys the hell out of me, when I've just scanned a man page to the information that I want, hit "q" and then the information disappears! What morons! :-) -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
export LESS='-X'
I read the help on less -X, but I don't understand why I'd want this?
Here's the answer:
Disables sending the termcap initialization and deinitialization strings to the terminal. This is sometimes desirable if the deinitialization string does something unnecessary, like clear- ing the screen.
every GNU-based system I've ever worked on clears the screen by default on exit from less. Annoys the hell out of me, when I've just scanned a man page to the information that I want, hit "q" and then the information disappears! What morons! :-)
YES!! you are the MAN!! -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes: [snip]
every GNU-based system I've ever worked on clears the screen by default on exit from less. Annoys the hell out of me, when I've just scanned a man page to the information that I want, hit "q" and then the information disappears! What morons! :-)
YES!! you are the MAN!!
Why, thank you. I knew I wasn't the only one who hated this. Glad to think it's helping someone - it took me ages to realize that it was configurable behaviour. -- Raoul Gough. export LESS='-X'
On Nov 26, 2003, at 1:55 PM, Raoul Gough wrote:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes: [snip]
every GNU-based system I've ever worked on clears the screen by default on exit from less. Annoys the hell out of me, when I've just scanned a man page to the information that I want, hit "q" and then the information disappears! What morons! :-)
YES!! you are the MAN!!
Why, thank you. I knew I wasn't the only one who hated this. Glad to think it's helping someone - it took me ages to realize that it was configurable behaviour.
You definitely are the man! It's always bothered me too, never looked into fixing it. Thanks! -bob
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 26 Nov 2003 at 11:17, Raoul Gough wrote:
every GNU-based system I've ever worked on clears the screen by default on exit from less. Annoys the hell out of me, when I've just scanned a man page to the information that I want, hit "q" and then the information disappears! What morons! :-)
I guess I'm too used to GUI-based programming - been doing it since 1990 - I use that Help application with KDE to view man pages. I just really, really wish it'd let you open more than one at once :( Other trick is to have many open terminals just for viewing man pages. Cheers, Niall -----BEGIN PGP SIGNATURE----- Version: idw's PGP-Frontend 4.9.6.1 / 9-2003 + PGP 8.0.2 iQA/AwUBP8UrrcEcvDLFGKbPEQLD2ACfasRvCvKYRopbjJzoVZiZ3rK12lEAn2uP iieCwvEGg4DXEKguCP3aZZIK =xwg/ -----END PGP SIGNATURE-----
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes: [snip]
The use of static constants in ContainerTraits is unattractive to me, because it's not particularly extensible. What about asking the user to provide an mpl::set of the property type tags:
typedef mpl::set<mutable,find,insert,push_back> capabilities;
or something?
Looks like a good idea. I'll give this a go.
We may need to whip mpl::set into shape. In the meantime you could use an mpl::vector, and mpl::find which will give slightly longer compiles but should work.
Actually, I'm not so sure about the benefits of making this change now. For instance, the current boolean flag approach is the same one used in std::numeric_limits. What would you think about using bitwise-combinations of flags? I've recently introduced this as a way to disable expensive features that you don't need, and it seems pretty convenient. The only drawback I can think of is a limitation (on many systems anyway) to 32 selectable properties. Is there anything else that using mpl::set or mpl::vector would get us in terms of functionality that bitsets (or seperate bools) don't have? -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes: [snip]
The use of static constants in ContainerTraits is unattractive to me, because it's not particularly extensible. What about asking the user to provide an mpl::set of the property type tags:
typedef mpl::set<mutable,find,insert,push_back> capabilities;
or something?
Looks like a good idea. I'll give this a go.
We may need to whip mpl::set into shape. In the meantime you could use an mpl::vector, and mpl::find which will give slightly longer compiles but should work.
Actually, I'm not so sure about the benefits of making this change now. For instance, the current boolean flag approach is the same one used in std::numeric_limits.
numeric_limits is hardly a model of good (based on the best information we have today) design.
What would you think about using bitwise-combinations of flags? I've recently introduced this as a way to disable expensive features that you don't need, and it seems pretty convenient. The only drawback I can think of is a limitation (on many systems anyway) to 32 selectable properties.
As you say, it's also limiting, but it's not terrible.
Is there anything else that using mpl::set or mpl::vector would get us in terms of functionality that bitsets (or seperate bools) don't have?
Yes. These symbolic tags can have operations built into them, so that when you process them you don't have to keep the knowledge about each one's meaning in one monolithic place. Instead you can let the tags themselves do the work, leading to better modularity and extensibility... at least, this may be possible. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes: [snip]
The use of static constants in ContainerTraits is unattractive to me, because it's not particularly extensible. What about asking the user to provide an mpl::set of the property type tags:
typedef mpl::set<mutable,find,insert,push_back> capabilities;
or something?
Looks like a good idea. I'll give this a go.
We may need to whip mpl::set into shape. In the meantime you could use an mpl::vector, and mpl::find which will give slightly longer compiles but should work.
Actually, I'm not so sure about the benefits of making this change now. For instance, the current boolean flag approach is the same one used in std::numeric_limits.
numeric_limits is hardly a model of good (based on the best information we have today) design.
What would you think about using bitwise-combinations of flags? I've recently introduced this as a way to disable expensive features that you don't need, and it seems pretty convenient. The only drawback I can think of is a limitation (on many systems anyway) to 32 selectable properties.
As you say, it's also limiting, but it's not terrible.
It's also very cheap in terms of compile time and mangled name lengths.
Is there anything else that using mpl::set or mpl::vector would get us in terms of functionality that bitsets (or seperate bools) don't have?
Yes. These symbolic tags can have operations built into them, so that when you process them you don't have to keep the knowledge about each one's meaning in one monolithic place. Instead you can let the tags themselves do the work, leading to better modularity and extensibility... at least, this may be possible.
Interesting. I was wondering about this, because just replacing tests like traits::has_mutable_ref with traits::property_set::includes<mutable_reference>::value doesn't seem like much of a win by itself. Being able to do something like "apply each property to this class_ instance" would be a different story. This would also provide a neater way of extending the suite with new Python methods, compared to the current visitor_helper hooks. On the other hand, some of the Python methods are provided only when multiple abilities are present, e.g. "sort" requires is_reorderable and value_traits_::less_than_comparable. Such decisions are currently localized in the visitor template, the "monolithic repository" of this knowledge. I'm not sure that it would make sense to have ContainerTraits provide a ready-made set of Python methods to inject instead of just describing the relevant capabilities of the container. i.e. I'm starting to think that the capabilities are better off being just on/off flags in one form or another. -- Raoul Gough. export LESS='-X'
David Abrahams <dave@boost-consulting.com> writes: [snip]
I don't understand is_reorderable. How is that different from
is_convertible< iterator_traits<C::iterator>::iterator_category , forward_iterator_tag
::value && is_non_const_lvalue_iterator<C::iterator>::value && is_assignable<C::value_type>::value
??
I realize we don't have is_assignable, but shouldn't you phrase this in terms of something fundamental like value_type assignability? We can ask all the other questions (see boost/iterator/is_lvalue_iterator.hpp).
It looks like assignability is the really important test for determining whether a container can be reordered (i.e. sorted or reversed). However, I can't think of any way to implement an is_assignable template. For instance, std::pair<const int, int> is not assignable, yet it doesn't have top-level const qualification, and it *does* have an operator= (which will produce a compile-time error if used) so I don't think any has_member_function test will help. If anyone can suggest a workable is_assignable, I'll use it to deduce is_reorderable, but otherwise I think I'll just stick with is_mutable_ref and explicit overrides for some containers (i.e. std::map) -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
[snip]
I don't understand is_reorderable. How is that different from
is_convertible< iterator_traits<C::iterator>::iterator_category , forward_iterator_tag
::value && is_non_const_lvalue_iterator<C::iterator>::value && is_assignable<C::value_type>::value
??
I realize we don't have is_assignable, but shouldn't you phrase this in terms of something fundamental like value_type assignability? We can ask all the other questions (see boost/iterator/is_lvalue_iterator.hpp).
It looks like assignability is the really important test for determining whether a container can be reordered (i.e. sorted or reversed). However, I can't think of any way to implement an is_assignable template.
Neither can anyone else, other than specializing for known types and asking the user to specialize for his own.
For instance, std::pair<const int, int> is not assignable, yet it doesn't have top-level const qualification, and it *does* have an operator= (which will produce a compile-time error if used) so I don't think any has_member_function test will help.
Right. But you can provide partial specializations for std::pair<const T, const U>, std::pair<T, const U>, std::pair<const T, U>.
If anyone can suggest a workable is_assignable, I'll use it to deduce is_reorderable, but otherwise I think I'll just stick with is_mutable_ref and explicit overrides for some containers (i.e. std::map)
I *think* I still think that's an inferior solution. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
[snip]
I don't understand is_reorderable. How is that different from
is_convertible< iterator_traits<C::iterator>::iterator_category , forward_iterator_tag
::value && is_non_const_lvalue_iterator<C::iterator>::value && is_assignable<C::value_type>::value
??
I realize we don't have is_assignable, but shouldn't you phrase this in terms of something fundamental like value_type assignability? We can ask all the other questions (see boost/iterator/is_lvalue_iterator.hpp).
It looks like assignability is the really important test for determining whether a container can be reordered (i.e. sorted or reversed). However, I can't think of any way to implement an is_assignable template.
Neither can anyone else, other than specializing for known types and asking the user to specialize for his own.
Well, there is already a ValueTraits concept, so I could easily add an "is_assignable" feature to this, and specialize it for the std::pair instances that std::map utilizes. That would probably tie up quite well with the existing equality_comparable and less_than_comparable. On the other hand, perhaps this does belong purely in the ContainerTraits concept. I wonder whether assignability is always a quality of a container (and all instances of it) or just the particular type of value stored in a particular instance. In the case of the STL containers, I think all template arguments are required to be Assignable types, and some of the containers (set and map) add const qualification somewhere in their value_type. I've just been taking a look at the unordered_set proposal at http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1518.pdf and it looks like the unordered_set::value_type is not const qualified, which would confuse any assignability determination based on the container's value_type directly. On the other had, the container only provides const iterators, so I guess this means that unordered_set<X>::iterator::value_type is "X const", and using the iterator's value type would still work.
For instance, std::pair<const int, int> is not assignable, yet it doesn't have top-level const qualification, and it *does* have an operator= (which will produce a compile-time error if used) so I don't think any has_member_function test will help.
Right. But you can provide partial specializations for std::pair<const T, const U>, std::pair<T, const U>, std::pair<const T, U>.
I guess the only potential problem is weirdo cases where the value type appears to be assignable but the container still isn't reorderable, in which case the client code would have to provide a custom-written ContainerTraits anyway. I'm thinking about some kind of a dirty std::set wrapper that pretends its value_type is mutable and uses const_cast internally. For motivation, see e.g. http://groups.google.com/groups?selm=3c939210.56671713%40news.earthlink.net or http://home.clara.net/raoulgough/map3/index.html
If anyone can suggest a workable is_assignable, I'll use it to deduce is_reorderable, but otherwise I think I'll just stick with is_mutable_ref and explicit overrides for some containers (i.e. std::map)
I *think* I still think that's an inferior solution.
It's really a question of how the client code helps the library out when it would get the wrong answer by itself. Possible options include specializing an is_assignable template, specializing a value_traits template or providing an alternative ContainerTraits class (the current method). -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
[snip]
I don't understand is_reorderable. How is that different from
is_convertible< iterator_traits<C::iterator>::iterator_category , forward_iterator_tag
::value && is_non_const_lvalue_iterator<C::iterator>::value && is_assignable<C::value_type>::value
??
I realize we don't have is_assignable, but shouldn't you phrase this in terms of something fundamental like value_type assignability? We can ask all the other questions (see boost/iterator/is_lvalue_iterator.hpp).
It looks like assignability is the really important test for determining whether a container can be reordered (i.e. sorted or reversed). However, I can't think of any way to implement an is_assignable template.
Neither can anyone else, other than specializing for known types and asking the user to specialize for his own.
Well, there is already a ValueTraits concept, so I could easily add an "is_assignable" feature to this, and specialize it for the std::pair instances that std::map utilizes. That would probably tie up quite well with the existing equality_comparable and less_than_comparable.
On the other hand, perhaps this does belong purely in the ContainerTraits concept. I wonder whether assignability is always a quality of a container (and all instances of it) or just the particular type of value stored in a particular instance. In the case of the STL containers, I think all template arguments are required to be Assignable types
Yes, but...
and some of the containers (set and map) add const qualification somewhere in their value_type.
...that fact tends to make the value_type not Assignable.
I've just been taking a look at the unordered_set proposal at http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1518.pdf and it looks like the unordered_set::value_type is not const qualified, which would confuse any assignability determination based on the container's value_type directly.
I'm not sure if that's intentional. I've asked.
On the other had, the container only provides const iterators, so I guess this means that unordered_set<X>::iterator::value_type is "X const", and using the iterator's value type would still work.
No, an iterator's value_type is never const. You can look at the mutability of its ``reference`` type, but: a. the standard seems to place no requirements on the reference type of forward iterators b. It barely places requirements on the reference type of bidirectional iterators (you have to look for implications in the reverse_iterator requirements). c. Even having a reference type which is a reference-to-non-const doesn't make the value_type assignable.
For instance, std::pair<const int, int> is not assignable, yet it doesn't have top-level const qualification, and it *does* have an operator= (which will produce a compile-time error if used) so I don't think any has_member_function test will help.
Right. But you can provide partial specializations for std::pair<const T, const U>, std::pair<T, const U>, std::pair<const T, U>.
I guess the only potential problem is weirdo cases where the value type appears to be assignable but the container still isn't reorderable, in which case the client code would have to provide a custom-written ContainerTraits anyway.
There are a number of wierdo cases, but it all comes down to properties of the value type.
I'm thinking about some kind of a dirty std::set wrapper that pretends its value_type is mutable and uses const_cast internally. For motivation, see e.g.
http://groups.google.com/groups?selm=3c939210.56671713%40news.earthlink.net
I can't imagine how you plan to use this technique in this case.
If anyone can suggest a workable is_assignable, I'll use it to deduce is_reorderable, but otherwise I think I'll just stick with is_mutable_ref and explicit overrides for some containers (i.e. std::map)
I *think* I still think that's an inferior solution.
It's really a question of how the client code helps the library out when it would get the wrong answer by itself.
Yep.
Possible options include specializing an is_assignable template, specializing a value_traits template or providing an alternative ContainerTraits class (the current method).
I am not so convinced any more that the current method is worse than the others. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
[snip]
On the other hand, perhaps this does belong purely in the ContainerTraits concept. I wonder whether assignability is always a quality of a container (and all instances of it) or just the particular type of value stored in a particular instance. In the case of the STL containers, I think all template arguments are required to be Assignable types
Yes, but...
and some of the containers (set and map) add const qualification somewhere in their value_type.
...that fact tends to make the value_type not Assignable.
Of course. I was just thinking about whether it's conceptually related to the template arguments or rather to some property of the container template. I guess it doesn't actually make much practical difference in terms of providing the necessary partial specializations.
I've just been taking a look at the unordered_set proposal at http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1518.pdf and it looks like the unordered_set::value_type is not const qualified, which would confuse any assignability determination based on the container's value_type directly.
I'm not sure if that's intentional. I've asked.
On the other had, the container only provides const iterators, so I guess this means that unordered_set<X>::iterator::value_type is "X const", and using the iterator's value type would still work.
No, an iterator's value_type is never const.
Hmmmmm... That's really a bit of a shame, since I go to so much trouble to pass const_iterator or iterator to the iterator_traits base class, depending on whether the container has top-level const qualification or not :-) Maybe this doesn't actually gain anything at all!
You can look at the mutability of its ``reference`` type, but:
a. the standard seems to place no requirements on the reference type of forward iterators
b. It barely places requirements on the reference type of bidirectional iterators (you have to look for implications in the reverse_iterator requirements).
c. Even having a reference type which is a reference-to-non-const doesn't make the value_type assignable.
Yes, you mentioned before that the reference type is not necessarily a reliable guide. In fact, the current code relies on the iterator's reference type and deduces the wrong value for "is_mutable" on some plaforms.
For instance, std::pair<const int, int> is not assignable, yet it doesn't have top-level const qualification, and it *does* have an operator= (which will produce a compile-time error if used) so I don't think any has_member_function test will help.
Right. But you can provide partial specializations for std::pair<const T, const U>, std::pair<T, const U>, std::pair<const T, U>.
I guess the only potential problem is weirdo cases where the value type appears to be assignable but the container still isn't reorderable, in which case the client code would have to provide a custom-written ContainerTraits anyway.
There are a number of wierdo cases, but it all comes down to properties of the value type.
I'm thinking about some kind of a dirty std::set wrapper that pretends its value_type is mutable and uses const_cast internally. For motivation, see e.g.
http://groups.google.com/groups?selm=3c939210.56671713%40news.earthlink.net
I can't imagine how you plan to use this technique in this case.
Maybe it's not really a robust solution, but you could just have wrappers that const_cast references from std::set or std::set::iterator to remove the container's const qualification. I'm thinking of cases where only a portion of the "value_type" is used as a sorting key, and the remainder can be mutated at will (and preferably in-place). The value_type is then some UDT (possibly with safeguards to prevent key modification) which may or may not be assignable. In fact, a vector of those values might well be reorderable, whereas the std::set wrapper container isn't. Still, this is stretching things a long way to try and find a counter-example.
If anyone can suggest a workable is_assignable, I'll use it to deduce is_reorderable, but otherwise I think I'll just stick with is_mutable_ref and explicit overrides for some containers (i.e. std::map)
I *think* I still think that's an inferior solution.
It's really a question of how the client code helps the library out when it would get the wrong answer by itself.
Yep.
Possible options include specializing an is_assignable template, specializing a value_traits template or providing an alternative ContainerTraits class (the current method).
I am not so convinced any more that the current method is worse than the others.
Oh no! I'm starting to think that the value_traits or is_assignable templates would actually be better solutions. I say "would be" because neither of them is at all convenient to do on MSVC6 owing to the lack of PTS. In fact, that practical difficulty probably means I'll stick with the current method, although I'm no longer convinced it is the best solution in theory. -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
[snip]
On the other hand, perhaps this does belong purely in the ContainerTraits concept. I wonder whether assignability is always a quality of a container (and all instances of it) or just the particular type of value stored in a particular instance. In the case of the STL containers, I think all template arguments are required to be Assignable types
Yes, but...
and some of the containers (set and map) add const qualification somewhere in their value_type.
...that fact tends to make the value_type not Assignable.
Of course. I was just thinking about whether it's conceptually related to the template arguments or rather to some property of the container template. I guess it doesn't actually make much practical difference in terms of providing the necessary partial specializations.
I've just been taking a look at the unordered_set proposal at http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1518.pdf and it looks like the unordered_set::value_type is not const qualified, which would confuse any assignability determination based on the container's value_type directly.
I'm not sure if that's intentional. I've asked.
On the other had, the container only provides const iterators, so I guess this means that unordered_set<X>::iterator::value_type is "X const", and using the iterator's value type would still work.
No, an iterator's value_type is never const.
Hmmmmm... That's really a bit of a shame, since I go to so much trouble to pass const_iterator or iterator to the iterator_traits base class, depending on whether the container has top-level const qualification or not :-)
What does this have to do with the _container's_ const qualification? I just mean that iterator_traits<I>::value_type is never a const type for any valid iterator I.
Possible options include specializing an is_assignable template, specializing a value_traits template or providing an alternative ContainerTraits class (the current method).
I am not so convinced any more that the current method is worse than the others.
Oh no! I'm starting to think that the value_traits or is_assignable templates would actually be better solutions.
OK, I don't feel strongly either way.
I say "would be" because neither of them is at all convenient to do on MSVC6 owing to the lack of PTS.
How does that come into play? It's my policy not to make major interface compromises for broken compilers.
In fact, that practical difficulty probably means I'll stick with the current method, although I'm no longer convinced it is the best solution in theory.
-- Dave Abrahams Boost Consulting www.boost-consulting.com
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
[snip]
On the other hand, perhaps this does belong purely in the ContainerTraits concept. I wonder whether assignability is always a quality of a container (and all instances of it) or just the particular type of value stored in a particular instance. In the case of the STL containers, I think all template arguments are required to be Assignable types
Yes, but...
and some of the containers (set and map) add const qualification somewhere in their value_type.
...that fact tends to make the value_type not Assignable.
Of course. I was just thinking about whether it's conceptually related to the template arguments or rather to some property of the container template. I guess it doesn't actually make much practical difference in terms of providing the necessary partial specializations.
I've just been taking a look at the unordered_set proposal at http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1518.pdf and it looks like the unordered_set::value_type is not const qualified, which would confuse any assignability determination based on the container's value_type directly.
I'm not sure if that's intentional. I've asked.
On the other had, the container only provides const iterators, so I guess this means that unordered_set<X>::iterator::value_type is "X const", and using the iterator's value type would still work.
No, an iterator's value_type is never const.
Hmmmmm... That's really a bit of a shame, since I go to so much trouble to pass const_iterator or iterator to the iterator_traits base class, depending on whether the container has top-level const qualification or not :-)
What does this have to do with the _container's_ const qualification? I just mean that iterator_traits<I>::value_type is never a const type for any valid iterator I.
Possible options include specializing an is_assignable template, specializing a value_traits template or providing an alternative ContainerTraits class (the current method).
I am not so convinced any more that the current method is worse than the others.
Oh no! I'm starting to think that the value_traits or is_assignable templates would actually be better solutions.
OK, I don't feel strongly either way.
I say "would be" because neither of them is at all convenient to do on MSVC6 owing to the lack of PTS.
How does that come into play? It's my policy not to make major interface compromises for broken compilers.
In fact, that practical difficulty probably means I'll stick with the current method, although I'm no longer convinced it is the best solution in theory.
-- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
[snip]
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
On the other hand, perhaps this does belong purely in the ContainerTraits concept. I wonder whether assignability is always a quality of a container (and all instances of it) or just the particular type of value stored in a particular instance. In the case of the STL containers, I think all template arguments are required to be Assignable types
Yes, but...
and some of the containers (set and map) add const qualification somewhere in their value_type.
...that fact tends to make the value_type not Assignable.
Of course. I was just thinking about whether it's conceptually related to the template arguments or rather to some property of the container template. I guess it doesn't actually make much practical difference in terms of providing the necessary partial specializations. Of course. I was just thinking about whether it's conceptually related to the template arguments or rather to some property of the container template. I guess it doesn't actually make much practical difference in terms of providing the necessary partial specializations.
I've figured out what was bugging me about this. For example, supporting std::map this way would require a partial specialization for std::pair<X const, Y>. More generally, there has to be a value_traits (or is_assignable) specialization for the container's value_type, which could be something non-obvious to the client code (e.g. container arguments X and Y, but must specialize on weird_thing<X, more_weirdness<Y> >). In the worst case, a container could use a nested class, for which you can't provide a partial specialization at all (non-deduced context and all that).
David Abrahams <dave@boost-consulting.com> writes: [snip]
No, an iterator's value_type is never const.
Hmmmmm... That's really a bit of a shame, since I go to so much trouble to pass const_iterator or iterator to the iterator_traits base class, depending on whether the container has top-level const qualification or not :-)
What does this have to do with the _container's_ const qualification?
I just mean that iterator_traits<I>::value_type is never a const type for any valid iterator I.
If the container is const qualified then begin() and end() return const_iterators, so the container_traits have to typedef the right iterator type. I also try to use the iterator information for is_reorderable (via has_mutable_ref): template<typename Container, typename ValueTraits = detail::no_override> struct base_container_traits : public ::boost::python::indexing::iterator_traits< BOOST_DEDUCED_TYPENAME mpl::if_< is_const<Container>, BOOST_DEDUCED_TYPENAME Container::const_iterator, BOOST_DEDUCED_TYPENAME Container::iterator >::type > Of course, top-level const also affects has_insert and so on, but those aren't related to the iterator type.
Possible options include specializing an is_assignable template, specializing a value_traits template or providing an alternative ContainerTraits class (the current method).
I am not so convinced any more that the current method is worse than the others.
Oh no! I'm starting to think that the value_traits or is_assignable templates would actually be better solutions.
OK, I don't feel strongly either way.
I'm not entirely convinced about this either, so I think I'll just do less work by leaving it "as is" :-)
I say "would be" because neither of them is at all convenient to do on MSVC6 owing to the lack of PTS.
How does that come into play? It's my policy not to make major interface compromises for broken compilers.
Good point. It's not that difficult I suppose, just providing an override for the container_traits ValueTraits parameter in the workaround templates like set_suite and map_suite. Otherwise it would all use value_traits<typename Container::value_type> and (without PTS) get the wrong answers. Changing subjects, I have thought of a good reason for using bitflags instead of separate "has_this" or "has_that" static bool consts. When adding new features, requiring a new constant (e.g. "is_serializable") would break any existing ContainerTraits implementations that don't have it. Adding a new bitflag value would not break anything, since older ContainerTraits simply wouldn't ever set the flag (and wouldn't get the new feature). The only downside is the syntactic mess this will probably create: BOOST_STATIC_CONSTANT (int, feature_flags = (base_class::feature_flags & ~(is_const<mumble> ? reorderable_flag : 0)) | (something_else ? another_flag : 0)); Then again, maybe it doesn't have to be soooo bad: private: BOOST_STATIC_CONSTANT (int, cancelled = is_const<mumble> ? reorderable_flag : 0; BOOST_STATIC_CONSTANT (int, added = something_else ? another_flag : 0); public: BOOST_STATIC_CONSTANT (int, feature_flags = (base_class::feature_flags & ~cancelled) | added); Any thoughts? -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
[snip]
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
On the other hand, perhaps this does belong purely in the ContainerTraits concept. I wonder whether assignability is always a quality of a container (and all instances of it) or just the particular type of value stored in a particular instance. In the case of the STL containers, I think all template arguments are required to be Assignable types
Yes, but...
and some of the containers (set and map) add const qualification somewhere in their value_type.
...that fact tends to make the value_type not Assignable.
Of course. I was just thinking about whether it's conceptually related to the template arguments or rather to some property of the container template. I guess it doesn't actually make much practical difference in terms of providing the necessary partial specializations. Of course. I was just thinking about whether it's conceptually related to the template arguments or rather to some property of the container template. I guess it doesn't actually make much practical difference in terms of providing the necessary partial specializations.
I've figured out what was bugging me about this. For example, supporting std::map this way would require a partial specialization for std::pair<X const, Y>. More generally, there has to be a value_traits (or is_assignable) specialization for the container's value_type, which could be something non-obvious to the client code (e.g. container arguments X and Y, but must specialize on weird_thing<X, more_weirdness<Y> >).
Well, you could specialize template <class T, class U> struct is_assignable<std::pair<T,U> > : mpl::and_<is_assignable<T>, is_assignable<U> > {}; But in general I understand what you're saying.
In the worst case, a container could use a nested class, for which you can't provide a partial specialization at all (non-deduced context and all that).
Yep, good point.
David Abrahams <dave@boost-consulting.com> writes: [snip]
No, an iterator's value_type is never const.
Hmmmmm... That's really a bit of a shame, since I go to so much trouble to pass const_iterator or iterator to the iterator_traits base class, depending on whether the container has top-level const qualification or not :-)
What does this have to do with the _container's_ const qualification?
I just mean that iterator_traits<I>::value_type is never a const type for any valid iterator I.
If the container is const qualified then begin() and end() return const_iterators, so the container_traits have to typedef the right iterator type. I also try to use the iterator information for is_reorderable (via has_mutable_ref):
template<typename Container, typename ValueTraits = detail::no_override> struct base_container_traits : public ::boost::python::indexing::iterator_traits< BOOST_DEDUCED_TYPENAME mpl::if_< is_const<Container>, BOOST_DEDUCED_TYPENAME Container::const_iterator, BOOST_DEDUCED_TYPENAME Container::iterator >::type >
Of course, top-level const also affects has_insert and so on, but those aren't related to the iterator type.
I still don't see what *that* has to do with the const-ness of an iterator's value_type. I can't make the connection.
I say "would be" because neither of them is at all convenient to do on MSVC6 owing to the lack of PTS.
How does that come into play? It's my policy not to make major interface compromises for broken compilers.
Good point. It's not that difficult I suppose, just providing an override for the container_traits ValueTraits parameter in the workaround templates like set_suite and map_suite. Otherwise it would all use value_traits<typename Container::value_type> and (without PTS) get the wrong answers.
Changing subjects, I have thought of a good reason for using bitflags instead of separate "has_this" or "has_that" static bool consts.
I wasn't suggesting that you use static bool consts.
When adding new features, requiring a new constant (e.g. "is_serializable") would break any existing ContainerTraits implementations that don't have it. Adding a new bitflag value would not break anything, since older ContainerTraits simply wouldn't ever set the flag (and wouldn't get the new feature).
That's why I was suggesting a capabilities should be indicated as a sequence of tag types.
The only downside is the syntactic mess this will probably create:
BOOST_STATIC_CONSTANT (int, feature_flags = (base_class::feature_flags & ~(is_const<mumble> ? reorderable_flag : 0)) | (something_else ? another_flag : 0));
Then again, maybe it doesn't have to be soooo bad:
private: BOOST_STATIC_CONSTANT (int, cancelled = is_const<mumble> ? reorderable_flag : 0;
BOOST_STATIC_CONSTANT (int, added = something_else ? another_flag : 0);
public: BOOST_STATIC_CONSTANT (int, feature_flags = (base_class::feature_flags & ~cancelled) | added);
Any thoughts?
See above. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
[snip]
I just mean that iterator_traits<I>::value_type is never a const type for any valid iterator I.
If the container is const qualified then begin() and end() return const_iterators, so the container_traits have to typedef the right iterator type. I also try to use the iterator information for is_reorderable (via has_mutable_ref):
template<typename Container, typename ValueTraits = detail::no_override> struct base_container_traits : public ::boost::python::indexing::iterator_traits< BOOST_DEDUCED_TYPENAME mpl::if_< is_const<Container>, BOOST_DEDUCED_TYPENAME Container::const_iterator, BOOST_DEDUCED_TYPENAME Container::iterator >::type >
Of course, top-level const also affects has_insert and so on, but those aren't related to the iterator type.
I still don't see what *that* has to do with the const-ness of an iterator's value_type. I can't make the connection.
Oh, right. The iterator_traits base class tries to figure out a value for is_reorderable. From what you're saying, this is doomed to failure because (a) the iterator reference type is unpredictable and (b) the iterator value_type is the same in both const_iterator and iterator. [snip]
Changing subjects, I have thought of a good reason for using bitflags instead of separate "has_this" or "has_that" static bool consts.
I wasn't suggesting that you use static bool consts.
That's what I have at the moment though, and I'm still wondering about whether to change it or not.
When adding new features, requiring a new constant (e.g. "is_serializable") would break any existing ContainerTraits implementations that don't have it. Adding a new bitflag value would not break anything, since older ContainerTraits simply wouldn't ever set the flag (and wouldn't get the new feature).
That's why I was suggesting a capabilities should be indicated as a sequence of tag types.
Yes, I now see how this would address the same issue. The problem I see with using mpl::set or such like is the cost/benefit trade off. I don't see any way to factor out the Python method registration code (the class_<>::def calls) into the tag types, since they don't represent that level of decision - they only describe container abilities, which in some cases must be combined before deciding what methods to register. I don't see them ever representing more than boolean values, in which case there's not much benefit in applying all that mpl machinery. As for costs, maybe it's just because I haven't used mpl::set before, but it seems to me to add complexity. I imagine it introduces additional compile-time costs, big debugging symbols and maybe insanely long error messages if something breaks (although I get them already, of course). -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
[snip]
I just mean that iterator_traits<I>::value_type is never a const type for any valid iterator I.
If the container is const qualified then begin() and end() return const_iterators, so the container_traits have to typedef the right iterator type. I also try to use the iterator information for is_reorderable (via has_mutable_ref):
template<typename Container, typename ValueTraits = detail::no_override> struct base_container_traits : public ::boost::python::indexing::iterator_traits< BOOST_DEDUCED_TYPENAME mpl::if_< is_const<Container>, BOOST_DEDUCED_TYPENAME Container::const_iterator, BOOST_DEDUCED_TYPENAME Container::iterator >::type >
Of course, top-level const also affects has_insert and so on, but those aren't related to the iterator type.
I still don't see what *that* has to do with the const-ness of an iterator's value_type. I can't make the connection.
Oh, right. The iterator_traits base class
What iterator_traits are we talking about here? The one I know about doesn't know anything about "reorderability".
tries to figure out a value for is_reorderable. From what you're saying, this is doomed to failure because (a) the iterator reference type is unpredictable and (b) the iterator value_type is the same in both const_iterator and iterator.
And regardless none of that tells you whether it's assignable.
[snip]
That's why I was suggesting a capabilities should be indicated as a sequence of tag types.
Yes, I now see how this would address the same issue. The problem I see with using mpl::set or such like is the cost/benefit trade off. I don't see any way to factor out the Python method registration code (the class_<>::def calls) into the tag types, since they don't represent that level of decision - they only describe container abilities, which in some cases must be combined before deciding what methods to register.
In that case all they offer is "infinite" extensibility.
I don't see them ever representing more than boolean values, in which case there's not much benefit in applying all that mpl machinery. As for costs, maybe it's just because I haven't used mpl::set before, but it seems to me to add complexity.
It does.
I imagine it introduces additional compile-time costs, big debugging symbols and maybe insanely long error messages if something breaks (although I get them already, of course).
Yeah, what's one more? ;-) -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
[snip]
template<typename Container, typename ValueTraits = detail::no_override> struct base_container_traits : public ::boost::python::indexing::iterator_traits< BOOST_DEDUCED_TYPENAME mpl::if_< is_const<Container>, BOOST_DEDUCED_TYPENAME Container::const_iterator, BOOST_DEDUCED_TYPENAME Container::iterator >::type >
Of course, top-level const also affects has_insert and so on, but those aren't related to the iterator type.
I still don't see what *that* has to do with the const-ness of an iterator's value_type. I can't make the connection.
Oh, right. The iterator_traits base class
What iterator_traits are we talking about here? The one I know about doesn't know anything about "reorderability".
::boost::python::indexing::iterator_traits. It provides some typedefs, has_copyable_iter, is_reorderable and index_style, although is_reorderable isn't reliable, for the reasons we are currently discussing.
tries to figure out a value for is_reorderable. From what you're saying, this is doomed to failure because (a) the iterator reference type is unpredictable and (b) the iterator value_type is the same in both const_iterator and iterator.
And regardless none of that tells you whether it's assignable.
That's right. Initially I thought that checking whether remove_reference<typename iter::reference> was const qualified would do the trick (well, except for std::map) but it doesn't seem to work on some libraries for std::set either. However, it seems ok for containers that are normally reorderable but have top-level const qualification. i.e. it looks like is_const<remove_reference<container::const_iterator::reference> > always gives the "right" answer for has_mutable_ref and therefore is_reorderable as well.
[snip]
That's why I was suggesting a capabilities should be indicated as a sequence of tag types.
Yes, I now see how this would address the same issue. The problem I see with using mpl::set or such like is the cost/benefit trade off. I don't see any way to factor out the Python method registration code (the class_<>::def calls) into the tag types, since they don't represent that level of decision - they only describe container abilities, which in some cases must be combined before deciding what methods to register.
In that case all they offer is "infinite" extensibility.
I don't see them ever representing more than boolean values, in which case there's not much benefit in applying all that mpl machinery. As for costs, maybe it's just because I haven't used mpl::set before, but it seems to me to add complexity.
It does.
I imagine it introduces additional compile-time costs, big debugging symbols and maybe insanely long error messages if something breaks (although I get them already, of course).
Yeah, what's one more? ;-)
True. Does mpl::set currently work? I seem to remember that you suggested using mpl::vector at the moment, which raised some doubt about this. -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
[snip]
template<typename Container, typename ValueTraits = detail::no_override> struct base_container_traits : public ::boost::python::indexing::iterator_traits< BOOST_DEDUCED_TYPENAME mpl::if_< is_const<Container>, BOOST_DEDUCED_TYPENAME Container::const_iterator, BOOST_DEDUCED_TYPENAME Container::iterator >::type >
Of course, top-level const also affects has_insert and so on, but those aren't related to the iterator type.
I still don't see what *that* has to do with the const-ness of an iterator's value_type. I can't make the connection.
Oh, right. The iterator_traits base class
What iterator_traits are we talking about here? The one I know about doesn't know anything about "reorderability".
::boost::python::indexing::iterator_traits. It provides some typedefs, has_copyable_iter, is_reorderable and index_style, although
This describes traits of containers, right? Calling something iterator_traits which doesn't describe traits of iterators is very confusing.
is_reorderable isn't reliable, for the reasons we are currently discussing.
tries to figure out a value for is_reorderable. From what you're saying, this is doomed to failure because (a) the iterator reference type is unpredictable and (b) the iterator value_type is the same in both const_iterator and iterator.
And regardless none of that tells you whether it's assignable.
That's right. Initially I thought that checking whether remove_reference<typename iter::reference> was const qualified would do the trick (well, except for std::map) but it doesn't seem to work on some libraries for std::set either. However, it seems ok for containers that are normally reorderable but have top-level const qualification. i.e. it looks like
is_const<remove_reference<container::const_iterator::reference> >
always gives the "right" answer for has_mutable_ref and therefore is_reorderable as well.
Ouch! That seems like it has to be pure luck. After all, for std::set, const_iterator == iterator is legal, and it's easy to imagine a set<T> iterator which returns T const& from dereference. Further, as I've been trying to tell you, the iterator's "reference" type is currently not constrained by the standard in many cases. Much better to use the same trick used in is_lvalue_iterator.
[snip]
That's why I was suggesting a capabilities should be indicated as a sequence of tag types.
Yes, I now see how this would address the same issue. The problem I see with using mpl::set or such like is the cost/benefit trade off. I don't see any way to factor out the Python method registration code (the class_<>::def calls) into the tag types, since they don't represent that level of decision - they only describe container abilities, which in some cases must be combined before deciding what methods to register.
In that case all they offer is "infinite" extensibility.
I don't see them ever representing more than boolean values, in which case there's not much benefit in applying all that mpl machinery. As for costs, maybe it's just because I haven't used mpl::set before, but it seems to me to add complexity.
It does.
I imagine it introduces additional compile-time costs, big debugging symbols and maybe insanely long error messages if something breaks (although I get them already, of course).
Yeah, what's one more? ;-)
True.
That's not to say I'm convinced it's a good idea. Infinite extensibility may not be important.
Does mpl::set currently work? I seem to remember that you suggested using mpl::vector at the moment, which raised some doubt about this.
see libs/mpl/test/set.cpp. You can try it yourself and find out. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
[snip]
Does mpl::set currently work? I seem to remember that you suggested using mpl::vector at the moment, which raised some doubt about this.
see libs/mpl/test/set.cpp. You can try it yourself and find out.
I've looked at the test cases, which I *think* I understand after looking at the preprocessor output. From what I can see, there are tests for empty and one-element sets only. If that really is the case, I don't find it very convincing. I'm tending towards the bitflag approach at the moment anyway. By the way, I've been wondering about what the container suite interface should look like after moving to feature sets instead of static boolean constants. I'm thinking along these lines: template< class Container, SOME_KIND_OF_SET features = supported_features<Container>, class Algorithms = algorithms<Container>
container_suite;
where supported_features does the traits-like work of figuring out what the container can support. This would allow client code to override the features explicitly if something is not needed. Curiously, I think the Algorithms implementation doesn't need to know this information itself, since it is up to the container_suite to decide what Algorithms functions to instantiate. Another option would be to determine the supported features within the existing container_traits framework, and provide an optional features_to_disable parameter to the container_suite. Any thoughts or preferences on this front? -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
[snip]
Does mpl::set currently work? I seem to remember that you suggested using mpl::vector at the moment, which raised some doubt about this.
see libs/mpl/test/set.cpp. You can try it yourself and find out.
I've looked at the test cases, which I *think* I understand after looking at the preprocessor output. From what I can see, there are tests for empty and one-element sets only. If that really is the case, I don't find it very convincing.
If zero one and two all work, then N works by induction. But anyway...
I'm tending towards the bitflag approach at the moment anyway.
OK.
By the way, I've been wondering about what the container suite interface should look like after moving to feature sets instead of static boolean constants. I'm thinking along these lines:
template< class Container, SOME_KIND_OF_SET features = supported_features<Container>, class Algorithms = algorithms<Container>
container_suite;
where supported_features does the traits-like work of figuring out what the container can support. This would allow client code to override the features explicitly if something is not needed. Curiously, I think the Algorithms implementation doesn't need to know this information itself, since it is up to the container_suite to decide what Algorithms functions to instantiate.
Another option would be to determine the supported features within the existing container_traits framework, and provide an optional features_to_disable parameter to the container_suite. Any thoughts or preferences on this front?
Nope; so far it sounds great. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
[snip]
Does mpl::set currently work? I seem to remember that you suggested using mpl::vector at the moment, which raised some doubt about this.
see libs/mpl/test/set.cpp. You can try it yourself and find out.
I've looked at the test cases, which I *think* I understand after looking at the preprocessor output. From what I can see, there are tests for empty and one-element sets only. If that really is the case, I don't find it very convincing.
If zero one and two all work, then N works by induction. But anyway...
Are we talking about a mathematical proof or testing strategy here :-) You would have to prove that for all i, correct(i) implies correct(i+1) and then go on to prove e.g. correct(0). Proving general things about code is hard though, so the i -> i+1 implication would be difficult. In this case, restricting the testing to 0 and 1 element sets completely ignores potential problems with ordering of elements. e.g. is set<a,b> == set<b,a> ???
I'm tending towards the bitflag approach at the moment anyway.
OK.
By the way, I've been wondering about what the container suite interface should look like after moving to feature sets instead of static boolean constants. I'm thinking along these lines:
template< class Container, SOME_KIND_OF_SET features = supported_features<Container>, class Algorithms = algorithms<Container>
container_suite;
where supported_features does the traits-like work of figuring out what the container can support. This would allow client code to override the features explicitly if something is not needed. Curiously, I think the Algorithms implementation doesn't need to know this information itself, since it is up to the container_suite to decide what Algorithms functions to instantiate.
Another option would be to determine the supported features within the existing container_traits framework, and provide an optional features_to_disable parameter to the container_suite. Any thoughts or preferences on this front?
Nope; so far it sounds great.
OK, thanks! I think I'll go with the supported_features approach. -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
If zero one and two all work, then N works by induction. But anyway...
Are we talking about a mathematical proof or testing strategy here :-) You would have to prove that for all i, correct(i) implies correct(i+1) and then go on to prove e.g. correct(0). Proving general things about code is hard though, so the i -> i+1 implication would be difficult. In this case, restricting the testing to 0 and 1 element sets completely ignores potential problems with ordering of elements.
e.g. is set<a,b> == set<b,a> ???
I wasn't really serious ;-> -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
If zero one and two all work, then N works by induction. But anyway...
Are we talking about a mathematical proof or testing strategy here :-) You would have to prove that for all i, correct(i) implies correct(i+1) and then go on to prove e.g. correct(0). Proving general things about code is hard though, so the i -> i+1 implication would be difficult. In this case, restricting the testing to 0 and 1 element sets completely ignores potential problems with ordering of elements.
e.g. is set<a,b> == set<b,a> ???
I wasn't really serious ;->
I should have known, even without a smiley! -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <RaoulGough@yahoo.co.uk> writes: [snip]
I've been wondering about what the container suite interface should look like after moving to feature sets instead of static boolean constants. I'm thinking along these lines:
template< class Container, SOME_KIND_OF_SET features = supported_features<Container>, class Algorithms = algorithms<Container>
container_suite; [snip]
Nope; so far it sounds great.
OK, thanks! I think I'll go with the supported_features approach.
This is how the new implementation is actually looking: template< class Container, unsigned int MethodMask = all_methods, // All supported by algorithms class Algorithms = algorithms<Container>
struct container_suite /* ... */; The second template parameter is an unsigned bitmask that gets combined with a "supported_methods" value provided by the Algorithms argument. It worked out this way because determining what features should be supported by default depends on the value type as well as the type of container (i.e. it needs to know equality_comparable and less_than_comparable from the value_traits template). Here is the new vector_traits template, which works out what methods to provide (by default) for instances of std::vector: template<typename Container, typename ValueTraits = detail::no_override> class vector_traits : public default_container_traits<Container, ValueTraits> { typedef default_container_traits<Container, ValueTraits> base_class; BOOST_STATIC_CONSTANT(bool, is_mutable = !is_const<Container>::value); public: typedef typename base_class::value_traits_type value_traits_type; BOOST_STATIC_CONSTANT( unsigned int, supported_methods = ( method_len | method_getitem | method_getitem_slice | detail::unsigned_if< value_traits_type::equality_comparable, method_index | method_contains | method_count >::value | detail::unsigned_if< is_mutable, method_setitem | method_setitem_slice | method_delitem | method_delitem_slice | method_reverse | method_append | method_insert | method_extend >::value | detail::unsigned_if< type_traits::ice_and< is_mutable, value_traits_type::less_than_comparable >::value, method_sort >::value )); // Never supported: method_iter, method_has_key }; In case you really wanted to know, unsigned_if looks like this: namespace detail { template<bool Cond, unsigned int TrueValue, unsigned int FalseValue = 0> struct unsigned_if { struct true_type { BOOST_STATIC_CONSTANT(unsigned int, value = TrueValue); }; struct false_type { BOOST_STATIC_CONSTANT(unsigned int, value = FalseValue); }; typedef typename mpl::if_c<Cond, true_type, false_type>::type result_type; BOOST_STATIC_CONSTANT(unsigned int, value = result_type::value); }; } I've tested this much under gcc 3.3.1 and MSVC6.0 and 7.1. So before I get too carried away and convert everything to this new style, does Dave, Joel, or anyone else have comments or suggestions? -- Raoul Gough. export LESS='-X'
Raoul Gough wrote:
This is how the new implementation is actually looking:
template< class Container, unsigned int MethodMask = all_methods, // All supported by algorithms class Algorithms = algorithms<Container>
struct container_suite /* ... */;
The second template parameter is an unsigned bitmask that gets combined with a "supported_methods" value provided by the Algorithms argument. It worked out this way because determining what features should be supported by default depends on the value type as well as the type of container (i.e. it needs to know equality_comparable and less_than_comparable from the value_traits template).
[snips]
I've tested this much under gcc 3.3.1 and MSVC6.0 and 7.1. So before I get too carried away and convert everything to this new style, does Dave, Joel, or anyone else have comments or suggestions?
Looks cool to me ;-) My only concern is: what if the bits of an unsigned int runs out? Unlikely? What if the methods identifiers are types instead in a special namespace and specifying the methods is done using an mpl typelist? Example: container_suite<C, mpl::list<method_len, method_getitem, method_getitem_slice> > -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
Joel de Guzman <joel@boost-consulting.com> writes:
Raoul Gough wrote:
This is how the new implementation is actually looking: template< class Container, unsigned int MethodMask = all_methods, // All supported by algorithms class Algorithms = algorithms<Container>
struct container_suite /* ... */; The second template parameter is an unsigned bitmask that gets combined with a "supported_methods" value provided by the Algorithms argument. It worked out this way because determining what features should be supported by default depends on the value type as well as the type of container (i.e. it needs to know equality_comparable and less_than_comparable from the value_traits template).
[snips]
I've tested this much under gcc 3.3.1 and MSVC6.0 and 7.1. So before I get too carried away and convert everything to this new style, does Dave, Joel, or anyone else have comments or suggestions?
Looks cool to me ;-) My only concern is: what if the bits of an unsigned int runs out? Unlikely? What if the methods identifiers are types instead in a special namespace and specifying the methods is done using an mpl typelist? Example:
One should at the very least use an unsigned long. You're only guaranteed 16 bits with unsigned int. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Joel de Guzman <joel@boost-consulting.com> writes: [snip]
Looks cool to me ;-) My only concern is: what if the bits of an unsigned int runs out? Unlikely? What if the methods identifiers are types instead in a special namespace and specifying the methods is done using an mpl typelist? Example:
One should at the very least use an unsigned long. You're only guaranteed 16 bits with unsigned int.
I thought about this, but figured there weren't any 16-bit compilers that would compile the rest of the code anyway. Are there any real platforms where the compiler supports all that template machinery and has 16-bit ints (maybe some configurations of gcc)? I suppose it doesn't actually cost anything to go to unsigned long... -- Raoul Gough. export LESS='-X'
Raoul Gough wrote:
David Abrahams <dave@boost-consulting.com> writes:
Joel de Guzman <joel@boost-consulting.com> writes:
[snip]
Looks cool to me ;-) My only concern is: what if the bits of an unsigned int runs out? Unlikely? What if the methods identifiers are types instead in a special namespace and specifying the methods is done using an mpl typelist? Example:
One should at the very least use an unsigned long. You're only guaranteed 16 bits with unsigned int.
I thought about this, but figured there weren't any 16-bit compilers that would compile the rest of the code anyway. Are there any real platforms where the compiler supports all that template machinery and has 16-bit ints (maybe some configurations of gcc)? I suppose it doesn't actually cost anything to go to unsigned long...
Maybe I ought to write the static bitset thing. I wrote one before. I'll see if I can get the prototype. There's one here: http://spirit.sourceforge.net/dl_more/Spirit_StaticSet.h I'll see if I can make it MPLish. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
Joel de Guzman <joel@boost-consulting.com> writes:
Raoul Gough wrote:
David Abrahams <dave@boost-consulting.com> writes:
Joel de Guzman <joel@boost-consulting.com> writes: [snip]
Looks cool to me ;-) My only concern is: what if the bits of an unsigned int runs out? Unlikely? What if the methods identifiers are types instead in a special namespace and specifying the methods is done using an mpl typelist? Example:
One should at the very least use an unsigned long. You're only guaranteed 16 bits with unsigned int. I thought about this, but figured there weren't any 16-bit compilers that would compile the rest of the code anyway. Are there any real platforms where the compiler supports all that template machinery and has 16-bit ints (maybe some configurations of gcc)? I suppose it doesn't actually cost anything to go to unsigned long...
Maybe I ought to write the static bitset thing. I wrote one before. I'll see if I can get the prototype. There's one here: http://spirit.sourceforge.net/dl_more/Spirit_StaticSet.h I'll see if I can make it MPLish.
It'd be easy to base it on vector_c<unsigned long, ....> -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Joel de Guzman <joel@boost-consulting.com> writes:
Raoul Gough wrote:
David Abrahams <dave@boost-consulting.com> writes:
Joel de Guzman <joel@boost-consulting.com> writes: [snip]
Looks cool to me ;-) My only concern is: what if the bits of an unsigned int runs out? Unlikely? What if the methods identifiers are types instead in a special namespace and specifying the methods is done using an mpl typelist? Example:
One should at the very least use an unsigned long. You're only guaranteed 16 bits with unsigned int. I thought about this, but figured there weren't any 16-bit compilers that would compile the rest of the code anyway. Are there any real platforms where the compiler supports all that template machinery and has 16-bit ints (maybe some configurations of gcc)? I suppose it doesn't actually cost anything to go to unsigned long...
Maybe I ought to write the static bitset thing. I wrote one before. I'll see if I can get the prototype. There's one here: http://spirit.sourceforge.net/dl_more/Spirit_StaticSet.h I'll see if I can make it MPLish.
It'd be easy to base it on vector_c<unsigned long, ....>
Something like this would be a good solution! Especially since it is possible to take the complement of a set (handy for saying "all features" or "all features except *this*"). However, it would need to have compile-time determination of set membership. Is this possible? -- Raoul Gough. export LESS='-X'
Raoul Gough wrote:
David Abrahams <dave@boost-consulting.com> writes:
Joel de Guzman <joel@boost-consulting.com> writes:
Raoul Gough wrote:
David Abrahams <dave@boost-consulting.com> writes:
Joel de Guzman <joel@boost-consulting.com> writes:
[snip]
Looks cool to me ;-) My only concern is: what if the bits of an unsigned int runs out? Unlikely? What if the methods identifiers are types instead in a special namespace and specifying the methods is done using an mpl typelist? Example:
One should at the very least use an unsigned long. You're only guaranteed 16 bits with unsigned int.
I thought about this, but figured there weren't any 16-bit compilers that would compile the rest of the code anyway. Are there any real platforms where the compiler supports all that template machinery and has 16-bit ints (maybe some configurations of gcc)? I suppose it doesn't actually cost anything to go to unsigned long...
Maybe I ought to write the static bitset thing. I wrote one before. I'll see if I can get the prototype. There's one here: http://spirit.sourceforge.net/dl_more/Spirit_StaticSet.h I'll see if I can make it MPLish.
It'd be easy to base it on vector_c<unsigned long, ....>
Yep. That's what I'm thinking.
Something like this would be a good solution! Especially since it is possible to take the complement of a set (handy for saying "all features" or "all features except *this*"). However, it would need to have compile-time determination of set membership. Is this possible?
Yep. Sure! -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
Joel de Guzman <joel@boost-consulting.com> writes:
Raoul Gough wrote:
David Abrahams <dave@boost-consulting.com> writes:
Joel de Guzman <joel@boost-consulting.com> writes: [snip]
Maybe I ought to write the static bitset thing. I wrote one before. I'll see if I can get the prototype. There's one here: http://spirit.sourceforge.net/dl_more/Spirit_StaticSet.h I'll see if I can make it MPLish.
It'd be easy to base it on vector_c<unsigned long, ....>
Yep. That's what I'm thinking.
Something like this would be a good solution! Especially since it is possible to take the complement of a set (handy for saying "all features" or "all features except *this*"). However, it would need to have compile-time determination of set membership. Is this possible?
Yep. Sure!
The only worry I see is the notational (or syntax) issue. How easy would it be to express the combination of possible values? For reference again, here is what it looks like with plain bits: BOOST_STATIC_CONSTANT( unsigned int, supported_methods = ( method_len | method_getitem | method_getitem_slice | detail::unsigned_if< value_traits_type::equality_comparable, method_index | method_contains | method_count >::value // ... Which is not really pretty, but I think it is understandable enough. Considering the following two questions: 1. What are the costs of supporting an effectively unlimited number of flags? 2. What is the likelihood that we would ever need more than 32 (there are currently 16)? What I'm thinking is, can we go with the simplest approach that works now, and switch to a more complex solution if it ever becomes necessary? Of course, it would be helpful to know what the above code would look like with a vector_c type solution. -- Raoul Gough. export LESS='-X'
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 23 Jan 2004 at 10:49, Raoul Gough wrote:
2. What is the likelihood that we would ever need more than 32 (there are currently 16)?
What I'm thinking is, can we go with the simplest approach that works now, and switch to a more complex solution if it ever becomes necessary? Of course, it would be helpful to know what the above code would look like with a vector_c type solution.
Surely you can use long long or __int64 as template parameters? Also, CUJ had an article about implementing infinite length numbers at compile time using templates. May be useful here. Cheers, Niall -----BEGIN PGP SIGNATURE----- Version: idw's PGP-Frontend 4.9.6.1 / 9-2003 + PGP 8.0.2 iQA/AwUBQBGC3sEcvDLFGKbPEQKNFgCcC5w1Hu8bdP2CjS4M697s57izWeQAn0wd wBHr4+g8fY5amp55FDmXQp0K =rpRB -----END PGP SIGNATURE-----
"Niall Douglas" <s_sourceforge@nedprod.com> writes:
On 23 Jan 2004 at 10:49, Raoul Gough wrote:
2. What is the likelihood that we would ever need more than 32 (there are currently 16)?
What I'm thinking is, can we go with the simplest approach that works now, and switch to a more complex solution if it ever becomes necessary? Of course, it would be helpful to know what the above code would look like with a vector_c type solution.
Surely you can use long long or __int64 as template parameters?
I guess so - on compilers that support one or the other. long long is (still) not part of the C++ standard, AFAIK.
Also, CUJ had an article about implementing infinite length numbers at compile time using templates. May be useful here.
I haven't seen that issue - is it available online? Anyway I would guess that the same worry about complexity and notation applies. It's a common question as to whether you should complicate the current implementation in preparation for possible extensions in the future. If those extensions never become necessary, you've created a lot more effort (including implementation, documentation, maintenance, user confusion, etc.) for no actual benefit. -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
"Niall Douglas" <s_sourceforge@nedprod.com> writes:
On 23 Jan 2004 at 10:49, Raoul Gough wrote:
2. What is the likelihood that we would ever need more than 32 (there are currently 16)?
What I'm thinking is, can we go with the simplest approach that works now, and switch to a more complex solution if it ever becomes necessary? Of course, it would be helpful to know what the above code would look like with a vector_c type solution.
Surely you can use long long or __int64 as template parameters?
I guess so - on compilers that support one or the other. long long is (still) not part of the C++ standard, AFAIK.
Also, CUJ had an article about implementing infinite length numbers at compile time using templates. May be useful here.
I haven't seen that issue - is it available online? Anyway I would guess that the same worry about complexity and notation applies.
It requires a conforming compiler, and provides no more flexibility than vector_c<...> Steve Dewhurst was doing it by representing numbers as array types: char[two_to_the_0][two_to_the_32][two_to_the_64]... It's cute, and probably takes fewer compile-time resources, but it's probably not better. -- Dave Abrahams Boost Consulting www.boost-consulting.com
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 24 Jan 2004 at 12:24, Raoul Gough wrote:
Surely you can use long long or __int64 as template parameters?
I guess so - on compilers that support one or the other. long long is (still) not part of the C++ standard, AFAIK.
If I remember the standard only guarantees some very short recursion depths for templates and macros which if observed, parts of Boost wouldn't compile. Also on most 64 bit compilers, long becomes 64 bit. We'll be in 64 bit land sooner than we might think. You're dammed if you do and dammed if you don't. My vote is that you choose whatever is the simplest, easiest to maintain mechanism with a bias towards faster compile times.
Also, CUJ had an article about implementing infinite length numbers at compile time using templates. May be useful here.
I haven't seen that issue - is it available online? Anyway I would guess that the same worry about complexity and notation applies. It's a common question as to whether you should complicate the current implementation in preparation for possible extensions in the future. If those extensions never become necessary, you've created a lot more effort (including implementation, documentation, maintenance, user confusion, etc.) for no actual benefit.
Yes the CUJ article I refer to is online - look in the experts forum. I have no income, therefore can't afford anything not free - hence the nasty 33k modem connection to the net I must put up with :( If I understand things correctly, these changes shouldn't affect client code ie; how I've used your indexing library won't require more than recompiling to use any changed mechanism you decide upon. Therefore it's perfectly reasonable to go with the simple method now if you maintain the option to enhance the internals later if demand requires it. Put it this way Raoul - you've done a bang up job on that suite, but some people would prefer what's done already now and aren't really too bothered if it's "perfect" or not, whatever "perfect" might be. Think of all the other useful projects you could be engaged upon! :) Ultimately Dave's the arbiter, if he's happy with long based bitmaps then it's cool. Dave's got a high quality threshold so if he okay's it, it's good enough. Cheers, Niall -----BEGIN PGP SIGNATURE----- Version: idw's PGP-Frontend 4.9.6.1 / 9-2003 + PGP 8.0.2 iQA/AwUBQBJ/BsEcvDLFGKbPEQIYCACaA9cJf6p7vyJungnEHqaF9BqyiqQAoKyb PYI/uomjDFxxytZj5JHwkogo =ttBd -----END PGP SIGNATURE-----
On 1/23/04 3:23 PM, "Niall Douglas" <s_sourceforge@nedprod.com> wrote: [SNIP]
Surely you can use long long or __int64 as template parameters? [TRUNCATE]
I don't think that's guaranteed to be supported by a compiler. -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com
Raoul Gough wrote:
The only worry I see is the notational (or syntax) issue. How easy would it be to express the combination of possible values? For reference again, here is what it looks like with plain bits:
BOOST_STATIC_CONSTANT( unsigned int, supported_methods = ( method_len | method_getitem | method_getitem_slice
| detail::unsigned_if< value_traits_type::equality_comparable, method_index | method_contains | method_count >::value
// ...
Which is not really pretty, but I think it is understandable enough. Considering the following two questions:
1. What are the costs of supporting an effectively unlimited number of flags?
2. What is the likelihood that we would ever need more than 32 (there are currently 16)?
What I'm thinking is, can we go with the simplest approach that works now, and switch to a more complex solution if it ever becomes necessary?
I agree.
Of course, it would be helpful to know what the above code would look like with a vector_c type solution.
If I get some time, I'll design and implement the static-bitset anyway regardless if it will be used or not. Only by then will I know what the interface will be. It's still rather sketchy at this point. Anyway, I'll surely need one for Spirit. -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
Joel de Guzman <joel@boost-consulting.com> writes:
Raoul Gough wrote: [snip]
I've tested this much under gcc 3.3.1 and MSVC6.0 and 7.1. So before I get too carried away and convert everything to this new style, does Dave, Joel, or anyone else have comments or suggestions?
Looks cool to me ;-) My only concern is: what if the bits of an unsigned int runs out? Unlikely? What if the methods identifiers are types instead in a special namespace and specifying the methods is done using an mpl typelist? Example:
container_suite<C, mpl::list<method_len, method_getitem, method_getitem_slice> >
Well, that's a good question. There are a number of possible methods that aren't included yet - things like pop, clear and the arithmetic operator support (__iadd__, __radd__, etc.) I haven't counted them up, but there are two possible solutions if the bitspace runs out: (1) select the new methods in groups (e.g. method_all_arithmetic) or (2) add a new unsigned template parameter for the "advanced" features. Dave and I discussed using a typelist, but I decided against them because of their complexity and my doubts about mpl::set, which would be the appropriate data structure in this case. Maybe it would be possible to do it with mpl::list - I'll have a look into it. BTW, aren't there compilers that have limited template recursion depth, which would also impose a restriction on the number of elements in a list/set? -- Raoul Gough. export LESS='-X'
participants (7)
-
Bob Ippolito -
Daryle Walker -
David Abrahams -
Joel de Guzman -
Niall Douglas -
Ralf W. Grosse-Kunstleve -
Raoul Gough