
Hi all, Peder and I have put together a combined version of our typeof implementations. The integrated library supports both compliant and vintage compilers, and can be found in the Boost sandbox CVS (boost/typeof, libs/typeof) or at: http://groups.yahoo.com/group/boost/files/typeof_integrated.zip As always, any comments are most welcome. Regards, Arkadiy

I read the following from the documents: =================================== The BOOST_TYPEOF_REGISTER_TEMPLATE_X macro accepts a template name and a preprocessor sequence describing template parameters, where each parameter should be described as one of the following: § class § typename § [unsigned] char § [unsigned] short § [unsigned] int § [unsigned] long § unsigned § bool For example: BOOST_TYPEOF_REGISTER_TEMPLATE_X(foo, (class)(unsigned int)(bool)); =================================== I wonder if other non-type template parameter is supported. For example: template <void (*)()> struct template_with_func_ptr_param {}; BOOST_TYPEOF_REGISTER_TEMPLATE_X( template_with_func_ptr_param, (void (*)()) ); // is this legal or possible? template <void (MyClass::*)(int)> struct template_with_mem_func_ptr_param {}; BOOST_TYPEOF_REGISTER_TEMPLATE_X( template_with_mem_func_ptr_param, (void (MyClass::*)(int)) ); // is this legal or possible? template <typename T, T t> struct template_with_dependent_non_type_param {}; BOOST_TYPEOF_REGISTER_TEMPLATE_X( template_with_dependent_non_type_param, (class)(/* what to put here? */)) ); // is this legal or possible? I didn't look into the implementation of the library. If I am missing something, please don't hesitate to point it out. Best regards, Allen

Hi Allen,
I wonder if other non-type template parameter is supported. For example:
Unfortunately no -- all we support is type and integral template parameters. The implementation is based on the ability to encode a type as an array of compile-time integers. Therefore, in order to support other non-type template parameters we would have to find a way to somehow convert them into compile-time integers. So far I don't see a satisfactory way of achieving this :( Regards, Arkadiy

Unfortunately no -- all we support is type and integral template
Two more questions: (1) Is template template parameter supported? (2) In your opinion, is it just *possible* to support complex non-type template parameters suppose no matter how ugly the user interface will be? In addition, I suggest adding a section in the document of the typeof library to mention the problems about complex non-type template parameters, dependendent non-type template parameters and template template parameters, including whether they are supported or not by the current library, and the possibility or main obstacles for supporting them in the future. parameters.
into
Regards, Yao, Zhen

"Allen Yao" <yaozhen@ustc.edu> wrote
(1) Is template template parameter supported?
They aren't.
It all depends on: 1) whether it is possible to represent this as a number of compile-time integers, and 2) whether it's possible to return this as a result of a meta-function. As far as my knowledge of the current state of template meta-programming goes, I don't see how it's possible. OTOH, 3 months ago I thought integral template parameters are impossible to support. And now, thanks to Peder, we do have them :).
Good idea. Actually there is one more limitation that keeps bothering me. It is related to nested classes, and most unfortunate because of iterators. IOW, we can't just register, e.g., std::vector<T>::const_iterator (as we do with std::vector<T>), and the user always have to register concrete classes, like std::vector<int>::const_iterator, std::vector<short>::const_iterator, etc., separately, as she needs them. This limitation comes from the "non-deduced context", and applies at least to the compliant implementation, but I think the vintage implementation should have the same problem :( Regards, Arkadiy

On Wed, 1 Dec 2004 21:21:02 -0800, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
That is correct. Just a thought on the subject: If we take the example with iterator deduction: given a metafunction is_iterator<> there may be a way around this problem: template<typename T> void deduce_iterator(std::vector<T>::iterator it) {...} template<typename T> void deduce_iterator(std::list<T>::iterator it) {...} template<typename T> void deduce_iterator(std::set<T>::iterator it) {...} struct select_deduce_iterator { template<typename T> static void deduce(const T& t) { deduce_iterator<T::value_type>(t); } }; template<typename T> void deduce_fallback(const T& t) { if_<is_iterator<T>, select_deduce_iterator, select_report_error,
Problem here of cource is that iterator also needs a difference_type from the container, which it gets from the allocator. It may be possible to construct a dummy allocator type with the correct difference_type just to get the types right. The above method relies on being hardwired into the system, but it should be possible to separate this functionality out by using SFINAE. Regards, Peder

Peder Holt wrote:
given a metafunction is_iterator<> there may be a way around this problem:
Problem is, it's impossible to write that metafunction. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On Thu, 02 Dec 2004 08:21:43 -0500, David Abrahams <dave@boost-consulting.com> wrote:
:( What a shame. For dinkumware stl (for VC6.5) it is possible to write a more specialized metafunction: is_stl_iterator<> as the relevant iterators has a common base class (vector<T> uses T*) Is this also feasible for other stl-implementations? Of course, this would only solve the problem for stl containers. The question is whether this is a common enough usage that it is advisable to implement support for it. Peder

Peder Holt wrote:
given a metafunction is_iterator<> there may be a way around this
"David Abrahams" <dave@boost-consulting.com> wrote problem:
Problem is, it's impossible to write that metafunction.
Well, it's not possible in general case, but for the purpose of typeof, a rough approximation may be enough. We can just assume that, if the type was not caught by all the specializations (generated by registration), then it *might be* one of the standard iterators. We can use SFINAE, examining value_type, distance_type, etc., to increase the probability of that assumption. The value_type then may be extracted, and using it, all the thing may be matched against pre-defined specializations for standard iterators, like: // call traits<It::value_type, It>::.... // specialization template<class T> class traits<T, vector<T>::iterator> { ... }; Now T can be deduced (at least by VC7.1). If our guess was wrong, and this is not a standard iterator after all, it will fail at this stage. The problem with this approach is that, also it's [usually] possible to extract value_type from the iterator, it's not true for allocators, predicates, etc., and so can work only for containers with defaults. Note that the problem is unfortunate mostly because of standard iterators. In general case, iterators can be developed as stand-alone templates, and typedef in the container can be used. These kind of iterators can be just registered as any other template. Arkadiy

Arkadiy Vertleyb wrote:
As long as you don't mind access violations when one of those typedefs happens to be present, but private. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote
I didn't think about it, and I didn't realise SFINAE can't handle private typedefs. However recall that this applies only to types not registered in a normal way. So, for these types only, we would get an error: can't access private typedef Foo::value_type instead of encode_type is not defined for the type Foo Not very nice, but arguably not an unreasonable price to pay for the ability to register standard iterators on the typeof library level... Unfortunately the problem doesn't seem to get solved anyway... Arkadiy

On Thu, 2 Dec 2004 11:28:44 -0500, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
It may be that we will need separate implementation for the different STL-implementations. I have looked at the stl-implementations of VC6.5, VC7.1,GCC 3.2 and STLport 4.5.3.
The iterators in dinkumware luckily have a common base class: std::iterator<> We can exploit this in order to make an implementation of is_stl_iterator<> When it comes to the allocator type, it is used only in generating template arguments to the iterator class. Here we can create a dummy allocator type that defines the correct typedefs, and we have solved the problem. But I agree, it seems impossible to create one unified solution to the problem. Peder
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Peder Holt" <peder.holt@gmail.com> wrote
Correct. It is just happens to be used by MSVC...
GCC 3.2
which is used for testing only, since it supports typeof natively...
and STLport typedefs global iterator types. In this case, we need only register these iterator types.
Correct.
But I agree, it seems impossible to create one unified solution to the
Can you ellaborate on the "dummy allocator" idea -- I am not sure I understand it. problem. Correct, even if all the STLs in the world used global iterator templates, they would use different ones, since it's not in the standard :-( Arkadiy

On Thu, 2 Dec 2004 16:54:15 -0500, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
Forget it :( I was missing a major point. Using a dummy allocator will only help deduce the iterators base class. Since the iterator class itself is defined inside the container, it will be dependent on all the template arguments of the container. My suggestion will only solve the problem for default arguments of the allocator and predicative, and not at all for maps. It is of cource possible to allow the user to register allocators, and thereby creating template specializations that will cover these, but the problem with predicatives and keys for maps still remain.

... Turns out that the problem can be solved rather elegantly (for VC6.5, anyway :) The following code compiles in VC 6.5 : #pragma warning (disable:4786) #include <map> #include <list> template<typename A0,typename A1> void deduce_container(std::list<A0,A1>::iterator) { int b=0; } template<typename A0,typename A1,typename A2,typename A3,typename A4> void deduce_container(std::_Tree<A0, A1, A2, A3, A4>::iterator) { int b=0; } void main() { std::map<int,double>::iterator a; std::list<int*>::iterator b; deduce_container(a); deduce_container(b); } (Note that std::set<A0,A1,A2>::iterator is a typedef, and can not be deduced. std::_Tree<...>::iterator is an nested class, and can be deduced) I don't know if this is legal for other compilers, but if it is, we should define a new macro: REGISTER_NESTED_TEMPLATE_CLASS(std::list,2,iterator) It would then be possible to solve the stl problem outside the typeof library, in e.g. the stl/register.hpp (With separate registrations for the different stl-implementations, of course) Peder

On Tue, 7 Dec 2004 08:35:16 +0100, Peder Holt <peder.holt@gmail.com> wrote:
... But this is nothing more than what you describe as a "non-deduced context" :( Can't be applied in the general case, but solves the stl iterators problem for selected compilers. Of course, if this doesn't compile with VC7.1, it is of no use anyway. Peder

On 12/07/2004 05:54 AM, Peder Holt wrote:
Peder, There's a workaround to non-deduced context, but using it requires specializations for each instantiation of the outer class. At least I think it works. I've used it with intel's compiler and it seems to work. A discussion of the workaround and a possible solution in a minor change to the language is discussed in: http://groups-beta.google.com/group/comp.std.c++/messages/ea2f9ccdabee9122,dd7fdb68f434be6d,013f08dccd789c33,fbf4388c37565c90,f406ed639436ca30?thread_id=ffee35abd2c61850&mode=thread&noheader=1#doc_f406ed639436ca30 HTH. Regards, Larry

"Larry Evans" <cppljevans@cox-internet.com> wrote
There's a workaround to non-deduced context, but using it requires specializations for each instantiation of the outer class.
Can't we then just register concrete iterators? BOOST_TYPEOF_REGISTER_TYPE(std::vector<int>::iterator); BOOST_TYPEOF_REGISTER_TYPE(std::map<int, std::string>::iterator); etc. Arkadiy

On 12/07/2004 09:53 AM, Arkadiy Vertleyb wrote:
OOPS. I guess you're right. I guess I was thinking that since it was some help in my problem (policy ptrs), then it would naturally extend to other cases. However, in my problem, there would be relatively few specializations; hence, I guess it was worthwhile. In the typeof case, I guess not. I'm still wondering whether the :0: token proposed in the mentioned post to c.s.c++ would solve the problem.

On Tue, 7 Dec 2004 11:45:47 -0500, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
... Then again, the following compiles with VC7.1, so maybe there is hope after all :) #pragma warning (disable:4786) #include <map> #include <list> #include <iostream> template<typename A0,typename A1> void deduce_container(class std::list<A0,A1>::iterator) { std::cout << "list" << "\n"; } template<typename A0> void deduce_container(class std::_Tree<A0>::iterator) { std::cout << "map" << "\n"; } int main() { std::map<int,double>::iterator a; std::list<int*>::iterator b; deduce_container(a); deduce_container(b); return 0; }

"Peder Holt" <peder.holt@gmail.com> wrote
Then again, the following compiles with VC7.1, so maybe there is hope after all :)
Wow... The reason it compiles is that you are using "class" where I used "typename". The following does not work: template<typename A0> void deduce_container(*typename* std::_Tree<A0>::iterator) { std::cout << "map" << "\n"; } I don't think this is a legal standard usage, though... Probably a Microsoft - specific "feature"... Any comments from language experts? Should the following work according to the Standard?
Arkadiy

On Wed, 8 Dec 2004 16:15:47 -0500, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
Correct. I first tried with typename.
I tried a modified version with comeau online compiler, and it did not compile. I like the syntax, though. There is a difference between nested classes and typedefs, and this is a nice way to show the difference explicitly in the source :) I have written a simple test in order to discover if other compilers support it: template<typename T> struct outer { class nested{}; }; template<typename T> void deduce(class outer<T>::nested) {} int main() { outer<int>::nested a; deduce(a); return 0; } Successfully compiles on VC6.5 and VC7.1 Fails to compile on Comeau C/C++ 4.3.3 I propose to define the macro BOOST_HAS_TEMPLATE_NESTED_CLASS_DEDUCTION for the VC compilers (and possibly other compilers supporting this) and supplying BOOST_TYPEOF_REGISTER_TEMPLATE_NESTED if the above is set. Peder

On Thu, 09 Dec 2004 06:44:00 -0700, Larry Evans <cppljevans@cox-internet.com> wrote:
Hmm. You have a point. The main reason for creating something like this would be to allow registration of the dinkumware iterators, which are defined as nested classes (unlike the iterators of other stl-implementations which are normal template classes already supported by the TYPEOF library) BOOST_TYPEOF_REGISTER_TEMPLATE_NESTED should only be used in this context, and not promoted outside of the TYPEOF library. This functionality could also be implemented in the same scope as the stl registration code. This would prevent the TYPEOF library from being polluted, but would allow automatic registration of iterators for all platforms. Peder
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Peder Holt" <peder.holt@gmail.com> wrote
Actually this method is only good with overloading -- doesn't work with partial template specialization. So, for the conformant implementation, we would have to implement some additional mechanism in the main template... So I am not sure we would be really able to "prevent the TYPEOF library from being polluted". Arkadiy

On Thu, 9 Dec 2004 10:05:24 -0500, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
Hmm. This is starting to look really ugly. I'll have one more go before abandoning this. We cannot place support for template nested class deduction directly into the typeof library: 1. It would break the elegance of the source 2. It exploits a compiler bug 3. It is only applicable for a single compiler series. I think I have found a way to separate the code from the library, given the restrictions above. Assuming that all the source will be placed in a compiler/stl-implementation specific folder: boost/typeof/stl/dinkumware_vc/ 1. Define the generic version of encode_type_impl (So far it has only been forward declared. 2. Create a template function encode_type_fn. 3. Use encode_type_fn to forward type deduction from encode_type_impl (Default implementation causes compile time failure with the proper error messages) 4. Overload encode_type_fn for each of the nested classes. The problem with this approach, is obviously that a function can only represent a single integral value at compile time, while we need a vector of them. The only way I know of to transfer a vector of integral values compile time across a function, is to use the compile time constants vector. Well, I guess it is back to square one. At least we tried. Peder

On 12/10/2004 01:58 AM, Larry Evans wrote:
Peder, it just occurred to me that instead of the proposed change of adding :0: as done in: http://groups-beta.google.com/group/comp.std.c++/messages/ea2f9ccdabee9122,dd7fdb68f434be6d,013f08dccd789c33,fbf4388c37565c90,f406ed639436ca30?thread_id=ffee35abd2c61850&mode=thread&noheader=1#doc_f406ed639436ca30 I'm supposing that if A<T>::B, which current means T is in a non-deduced context, were changed to mean A<T>:0:B as in the above proposal, then everything would work, AFAICT. IOW, no change is needed in the syntax, only change is needed in the meaning of non-deduced contexts. Instead of non-deduced context, rename to nested context. In other words: A<T>::B would mean B is nested in the "immediate" A<T> class and not in any superclass of A<T>. This would avoid the problem cited in: http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=uvflpetzg.fsf%40boost-consulting.com Does this seem like it would work?

On Fri, 10 Dec 2004 03:09:23 -0700, Larry Evans <cppljevans@cox-internet.com> wrote:
Probably, but it still won't work with existing compilers. The typeof library was created in order to support typeof until the time that this is included in the standard. Compiler support for typeof will probably be available before the definition of non-deduced-context is changed. Apart from that, I support your proposal. Peder
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 12/10/2004 03:09 AM, Larry Evans wrote: [snip]
Does this seem like it would work?
OOPS. Looking a little further found: http://groups-beta.google.com/group/comp.lang.c++.moderated/messages/9c5e6246d3692d0b,21e80ea0a448980f,5c284ab281122340,aecdeff994a3ab23,b96640f2c4b1082a,9248e91f9a4a0537,84b594817eabf9b7?thread_id=7d5c262634d45137&mode=thread&noheader=1#doc_21e80ea0a448980f where the problem with typedef's is mentioned as the show-stopper.

On Fri, 10 Dec 2004 03:50:58 -0700, Larry Evans <cppljevans@cox-internet.com> wrote:
Still, the problem in his post applies to typedefs. If A<T>::B is a nested class or struct under A<T>, and not a typedef, deduction should always be possible. In the case where B is a typedef: typedef typename some_class<T> B; you can deduce some_class<T> instead of A<T>::B Peder
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 12/10/2004 03:19 AM, Peder Holt wrote: [snip]
Do you mean in the case of Roni's example, that you can deduce by substitution, i.e. can_deduce: select<B, int, int *>::type --substitute--> can_deduce: select<(C1<T>::value != C2<T>::value), int, int *>::type ?

On Fri, 10 Dec 2004 04:49:41 -0700, Larry Evans <cppljevans@cox-internet.com> wrote:
Nope. can_deduce<T>::type is either int or int*, so we need to make specializations for int and int*, and can ignore can_deduce<T> altogether. Type deduction of nested typedefs would as far as I can see require that can_deduce<T>::type be a separate type from int and int*.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Peder Holt wrote:
No, you can't. Given some_class<V> as input to the pattern A<T>::B, you have no way to deduce T. template<class T> struct A { typedef typename arbitrarily_complex_metafunction<T>::type B; }; And of course getting back to iterators, you have no way of determining whether T* is T*, vector<T, A>::iterator, or basic_string<T, Tr, A>::iterator, much less deducing A or Tr.

On Fri, 10 Dec 2004 14:54:26 +0200, Peter Dimov <pdimov@mmltd.net> wrote:
What I was trying to say, was that, given that there are no nested classes involved, arbitrarily_complex_metafunction<T>::type will in the end be reduced to arbitrary_complex_type<A0,A1,A2,...>, which is a concrete type which can be deduced. For the typeof library this is sufficient. On the other hand: template<class T> struct A { class B; }; A<T>::B now should give sufficient information to be deduced.
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Peder Holt" <peder.holt@gmail.com> wrote
Please note that, as Peder has mentioned, the language support for typeof is probably going to be in the Standard before any other changes. Therefore, even if the changes related to the non-deduced context may be a valuable addition to the Standard, I don't think this is relevant to the typeof library -- we have to live with what we have... Arkadiy
participants (6)
-
Allen Yao
-
Arkadiy Vertleyb
-
David Abrahams
-
Larry Evans
-
Peder Holt
-
Peter Dimov