From: Matt L. <mat...@gm...> - 2008-03-13 19:51:13
|
I've discovered the first casualty caused by bring tr1 into vcl; it's vcl_swap. The problem is actually caused by the fact that I'm not folding tr1 into std. The function swap is commonly overloaded in std for all the types you might want to swap in a specialized, more efficient way. The multiple definitions of vcl_swap didn't cause a problem before because vcl_swap was always defined to std::swap regardless of argument types. Now there is a new swap function in <tr1/memory> for the shared_ptr type. So vcl wants to define vcl_swap as std::tr1::swap. This is a problem. We can't define the same symbol twice depending on the function arguments. Again, there are several solutions but none that I see are clean and elegant. Suggestions? Thanks, Matt |
From: Brad K. <bra...@ki...> - 2008-03-13 20:15:23
|
Matt Leotta wrote: > I've discovered the first casualty caused by bring tr1 into vcl; it's > vcl_swap. The problem is actually caused by the fact that I'm not > folding tr1 into std. The function swap is commonly overloaded in std > for all the types you might want to swap in a specialized, more > efficient way. The multiple definitions of vcl_swap didn't cause a > problem before because vcl_swap was always defined to std::swap > regardless of argument types. Now there is a new swap function in > <tr1/memory> for the shared_ptr type. So vcl wants to define vcl_swap > as std::tr1::swap. This is a problem. We can't define the same > symbol twice depending on the function arguments. > > Again, there are several solutions but none that I see are clean and > elegant. Suggestions? There are actually many standard headers that are documented to define std::swap overloads. Each vcl_* header needs to define the vcl_swap overloads its corresponding system header is supposed to provide. For example: // vcl_string.h template<class charT, class traits, class Allocator> void vcl_swap(vcl_basic_string<charT,traits,Allocator>& x, vcl_basic_string<charT,traits,Allocator>& y) { std::swap(x, y); } // vcl_deque.h template <class T, class Allocator> void vcl_swap(vcl_deque<T,Allocator>& x, vcl_deque<T,Allocator>& y) { std::swap(x, y); } // vcl_vector.h template <class T, class Allocator> void vcl_swap(vcl_vectory<T,Allocator>& x, vcl_vectory<T,Allocator>& y) { std::swap(x, y); } // vcl_list.h template <class T, class Allocator> void vcl_swap(vcl_list<T,Allocator>& x, vcl_list<T,Allocator>& y) { std::swap(x, y); } ...and so on for map, multimap, set, multiset, and finally // vcl_algorithm.h template<class T> void vcl_swap(T& x, T& y) { std::swap(x, y); } Then you can add the same thing in the tr1/memory header too. Note that the macro would be just #define vcl_swap vcl_swap -Brad |
From: Matt L. <mat...@gm...> - 2008-03-13 20:55:10
|
Brad, Thanks. This looks like a reasonable solution, but it's also a bit messy and time consuming to implement. If it has to be done, then it has to be done, but are there any other commonly overloaded symbols in std? I wouldn't want to do this for every new overloaded symbol we encounter in tr1. Also, can we guarantee that these wrappers will be inlined? Anyone else have a solution for comparison? Thanks, Matt On Thu, Mar 13, 2008 at 4:15 PM, Brad King <bra...@ki...> wrote: > > Matt Leotta wrote: > > I've discovered the first casualty caused by bring tr1 into vcl; it's > > vcl_swap. The problem is actually caused by the fact that I'm not > > folding tr1 into std. The function swap is commonly overloaded in std > > for all the types you might want to swap in a specialized, more > > efficient way. The multiple definitions of vcl_swap didn't cause a > > problem before because vcl_swap was always defined to std::swap > > regardless of argument types. Now there is a new swap function in > > <tr1/memory> for the shared_ptr type. So vcl wants to define vcl_swap > > as std::tr1::swap. This is a problem. We can't define the same > > symbol twice depending on the function arguments. > > > > Again, there are several solutions but none that I see are clean and > > elegant. Suggestions? > > There are actually many standard headers that are documented to define > std::swap overloads. Each vcl_* header needs to define the vcl_swap > overloads its corresponding system header is supposed to provide. For > example: > > // vcl_string.h > template<class charT, class traits, class Allocator> > void vcl_swap(vcl_basic_string<charT,traits,Allocator>& x, > vcl_basic_string<charT,traits,Allocator>& y) > { > std::swap(x, y); > } > > // vcl_deque.h > template <class T, class Allocator> > void vcl_swap(vcl_deque<T,Allocator>& x, vcl_deque<T,Allocator>& y) > { > std::swap(x, y); > } > > // vcl_vector.h > template <class T, class Allocator> > void vcl_swap(vcl_vectory<T,Allocator>& x, vcl_vectory<T,Allocator>& y) > { > std::swap(x, y); > } > > // vcl_list.h > template <class T, class Allocator> > void vcl_swap(vcl_list<T,Allocator>& x, vcl_list<T,Allocator>& y) > { > std::swap(x, y); > } > > ...and so on for map, multimap, set, multiset, and finally > > // vcl_algorithm.h > template<class T> > void vcl_swap(T& x, T& y) > { > std::swap(x, y); > } > > Then you can add the same thing in the tr1/memory header too. Note that > the macro would be just > > #define vcl_swap vcl_swap > > -Brad > > |
From: Brad K. <bra...@ki...> - 2008-03-13 21:02:48
|
Matt Leotta wrote: >> // vcl_string.h >> template<class charT, class traits, class Allocator> >> void vcl_swap(vcl_basic_string<charT,traits,Allocator>& x, >> vcl_basic_string<charT,traits,Allocator>& y) >> { >> std::swap(x, y); >> } > > Thanks. This looks like a reasonable solution, but it's also a bit > messy and time consuming to implement. If it has to be done, then it > has to be done, but are there any other commonly overloaded symbols in > std? I wouldn't want to do this for every new overloaded symbol we > encounter in tr1. IIRC swap is the only one in C++98 (for stl at least...there are also math ones for float/double/complex<float>/complex<double> that we already have). I think there will be a "move" version of all those swap functions in C++0x. > Also, can we guarantee that these wrappers will be inlined? It is never a guarantee, but very likely. Adding the inline keyword won't hurt either. -Brad |
From: Amitha P. <ami...@us...> - 2008-04-03 15:52:51
|
Sorry for the long delay in responding. So, the issue at hand is overloads for things like std::swap. Typically, vcl_swap is defined to be std::swap. But tr1 produces it's own versions of swap, in std::tr1::swap. Looking forward to C++0x, we'd like to avoid introducing vcl_tr1_swap. So, we'd also like vcl_swap to be defined to std::tr1::swap, which conflicts with the other definition. There are a couple of solutions: 1. A solution that Matt initially suggested was to fold the std::tr1 namespace into the std namespace. The problem with that is that it introduces symbols into the std namespace that do not exist now, and could thus cause conflicts. However, they will exist in the next C++ standard, and so it will cause conflicts at some point. 2. Brad suggested that for the conflicting functions, like vcl_swap, that we list all the overloads required by the standard, and implement them by calling the appropriate library-provided function, either std::swap or std::tr1::swap, in this case. The main problem with this approach is having to explicitly list all the required overloads. Taking this to the logical conclusion, we would be defining a complete C++ standard library, albeit a "thin implementation", one that borrows the implementation from the system. 3. We could do a version of (1) by introducing a vcl namespace, and folding both std and std::tr1 into vcl. Then, vcl_swap can be defined to be vcl::swap. This should work with all new compilers, but may not work with some of the older compilers. In previous emails, I advocated against (1), but now I think it's not too bad: if vcl is going to track C++0x, then the conflicts are going to happen "soon" anyway. (3) is essentially the same as (1), but has the advantage that we don't mess with the std namespace. On the issue of supporting old compilers for other projects, I've asked Luis Ibanez to provide a dashboard build with VS6 for vcl,vnl,netlib, and whatever else they care about (and only the things they care about). This will allow us to move forward with vxl without unduly affecting others. I think we can request the same of anyone else that depends on vxl: provide a dashboard build with your configuration, and we can try to support it, or decide as a group that we will not. Some questions that we have to decide on: A. Should vcl (try to) track C++0x as best it can? B. Should vcl have configuration options (like VCL_ENABLE_CXX0X)? C. Should all vcl features be available on all supported compilers, or should be be on a best-effort basis? (Within reason, of course.) My opinions are: We should try to track C++0x, and introduce new symbols from it into vcl without hesitation. This may cause some broken client code, but we should make sure that any breakage would have occurred anyway if the client moved to C++0x. We should not provide an ENABLE_CXX0X option. There should only be one vcl. If we where to provide an option, writing code with vcl would need many, many workarounds and #ifdefs, and that defeats the purpose of vcl. We should, however, provide a query facility (VCL_HAS_SHARED_POINTER) for those folks that want to implement workarounds for broken compilers. We should implement on a best-effort basis, with a feature being introduced into vcl if it is implemented on all reasonably new compilers. Trying to use the feature on an older compiler will cause an error. Users can then query for the capability and write a workaround if they want. (Or provide an implementation for that compiler.) On implementation, my preference is (3), (1), then (2). I put (2) last because it would involve a lot of work in vcl. I think vcl should be as thin as possible, and not introduce any new real functions. (I'm considering namespace vcl { using namespace std; } as not introducing any real functions.) What do others think? Amitha. |
From: Brad K. <bra...@ki...> - 2008-04-03 17:29:45
|
Amitha Perera wrote: > 3. We could do a version of (1) by introducing a vcl namespace, and > folding both std and std::tr1 into vcl. Then, vcl_swap can be defined > to be vcl::swap. This should work with all new compilers, but may not > work with some of the older compilers. [snip] > On implementation, my preference is (3), (1), then (2). I put (2) last > because it would involve a lot of work in vcl. I think vcl should be as > thin as possible, and not introduce any new real functions. (I'm > considering > namespace vcl { using namespace std; } > as not introducing any real functions.) See my previous argument for why we cannot do that: http://sourceforge.net/mailarchive/message.php?msg_name=47D75DCA.1030207%40kitware.com We could do this though: namespace vcl { using std::swap; using std::tr1::swap; } #define vcl_swap vcl::swap -Brad |
From: Amitha P. <ami...@us...> - 2008-04-03 17:57:15
|
Brad King wrote: > Amitha Perera wrote: >> namespace vcl { using namespace std; } > > See my previous argument for why we cannot do that: Fair enough. I'd forgotten. > namespace vcl > { > using std::swap; > using std::tr1::swap; > } > #define vcl_swap vcl::swap This is what I had in mind anyway. This is "easy" to do, and only requires a list of names (which we already have in vcl, thanks to Fred S., Andrew F., Matt L.), instead of requiring the full declarations for each of these. I think. Maybe actually implementing this scheme is just as difficult. Amitha. |
From: Brad K. <bra...@ki...> - 2008-04-03 18:01:30
|
Amitha Perera wrote: > Brad King wrote: >> Amitha Perera wrote: >>> namespace vcl { using namespace std; } >> >> See my previous argument for why we cannot do that: > > Fair enough. I'd forgotten. > >> namespace vcl >> { >> using std::swap; >> using std::tr1::swap; >> } >> #define vcl_swap vcl::swap > > This is what I had in mind anyway. This is "easy" to do, and only > requires a list of names (which we already have in vcl, thanks to Fred > S., Andrew F., Matt L.), instead of requiring the full declarations for > each of these. > > I think. Maybe actually implementing this scheme is just as difficult. It can be done for just the few names that are overloaded in both std and std::tr1 namespaces. The goal is to define vcl_swap, not to allow people to write "vcl::", at least for now. -Brad |
From: Amitha P. <ami...@us...> - 2008-04-03 18:08:53
|
Brad King wrote: > It can be done for just the few names that are overloaded in both std > and std::tr1 namespaces. The goal is to define vcl_swap, not to allow > people to write "vcl::", at least for now. Yes, but it doesn't generalize easily. We'd have to comb through the standard for every instance of swap, copy the declaration, and implement via a pass-through. Amitha. |
From: Brad K. <bra...@ki...> - 2008-04-03 18:50:28
|
Amitha Perera wrote: > Brad King wrote: >> It can be done for just the few names that are overloaded in both std >> and std::tr1 namespaces. The goal is to define vcl_swap, not to allow >> people to write "vcl::", at least for now. > > Yes, but it doesn't generalize easily. We'd have to comb through the > standard for every instance of swap, copy the declaration, and implement > via a pass-through. Huh? I was just pointing out that we don't have to do the "using" trick for every name right now. Just the ones that are in both "std::" and "std::tr1::" need to be done that way. -Brad |
From: Amitha P. <ami...@us...> - 2008-04-03 19:13:52
|
Brad King wrote: > Huh? I was just pointing out that we don't have to do the "using" trick > for every name right now. Just the ones that are in both "std::" and > "std::tr1::" need to be done that way. Sorry, my brain was somehow thinking of your solution of explicitly defining vcl_swap functions. Yes, you are right: the using trick could be used just for the conflicting variables. However, given that vcl/generic and vcl/iso (IIRC) are generated from a perl script, it may be easier to do it for everything. Anyhow, I'll try it at some point "soon". Amitha. |
From: Matt L. <mat...@gm...> - 2008-04-03 19:59:35
|
I'm in favor of putting everything in a vcl namespace, even if we still need to use macros to define vcl_foo as vcl::foo. This would be step in to direction of eventually using "vcl::" directly. In the mean time any troublesome compiler can still define vcl_foo as std::foo. If Amitha finds some other unseen problem with this approach, I think a good second choice is the use of the vcl namespace only for conflicting symbols like "swap" (as suggested by Brad). As for the other topics: A. I have no problem with introducing new symbols from C++0x into vcl without hesitation. However, I am concerned about where these new symbols can be used in VXL. Maybe we need another "not-in-core-for-now" restriction. We can't just start replacing vbl_smart_ptr with vcl_shared_ptr if the shared_ptr is only supported on a few platforms. Or are you suggesting that we can use them anywhere as long as we provided an ifdef'ed non-C++0x alternative? B. I agree that we shouldn't have an ENABLE_CXX0X option once we have the vcl infrastructure for handling C++0x in place. When we have a working solution for bringing together std and std::tr1, it can go. C. I think vcl features will have to be implemented on a best effort basis. After looking into shared_ptr I'm convinced that some of the C++0x new features will be incredibly difficulty to write generic versions of. Much of the new stuff is geared toward multi-threading and requires a lot of low level system specific interaction. Even classes like the shared_ptr have these dependencies so that they can make guarantees about their operation in a multi-threaded environment. We could write striped down versions that are not thread safe, but that seems to defeat the purpose of moving to the C++0x shared_ptr. Matt On Thu, Apr 3, 2008 at 3:13 PM, Amitha Perera <ami...@us...> wrote: > Brad King wrote: > > > Huh? I was just pointing out that we don't have to do the "using" trick > > for every name right now. Just the ones that are in both "std::" and > > "std::tr1::" need to be done that way. > > > > Sorry, my brain was somehow thinking of your solution of explicitly > defining vcl_swap functions. > > Yes, you are right: the using trick could be used just for the conflicting > variables. > > However, given that vcl/generic and vcl/iso (IIRC) are generated from a > perl script, it may be easier to do it for everything. Anyhow, I'll try it > at some point "soon". > > Amitha. > |
From: Peter V. <pet...@ya...> - 2008-04-03 21:28:52
|
> I'm in favor of putting everything in a vcl namespace, even if > we still need to use macros to define vcl_foo as vcl::foo. > This would be step in to direction of eventually using > "vcl::" directly. Actually, the whole point of vcl, from its perception on, was that it should gradually vanish as time passes and std:: gets fully adopted by all compilers we care for. So I would not move towards a vcl:: situation, but rather see if we indeed are arriving at the point where "vcl_" can be gradually replaced by "std::" (and "#include <vcl_FOO.h>" by "#include <FOO>"). This way the v*l libraries will have a more "standard" look and hence will be more easily usable within many C++ projects. (The whole "vcl_" business has been frightening some people to use vxl!) (Just my 2c...) -- Peter. -- __________________________________________________________ Går det långsamt? Skaffa dig en snabbare bredbandsuppkoppling. Sök och jämför hos Yahoo! Shopping. http://shopping.yahoo.se/c-100015813-bredband.html?partnerId=96914325 |
From: Matt L. <mat...@gm...> - 2008-04-03 23:01:56
|
On Thu, Apr 3, 2008 at 5:28 PM, Peter Vanroose <pet...@ya...> wrote: > > I'm in favor of putting everything in a vcl namespace, even if > > we still need to use macros to define vcl_foo as vcl::foo. > > This would be step in to direction of eventually using > > "vcl::" directly. > > Actually, the whole point of vcl, from its perception on, was that > it should gradually vanish as time passes and std:: gets fully > adopted by all compilers we care for. The problem is that VXL supports a moving window of compilers. On the leading edge, we have new standard features that we want to use without waiting for all compilers in the window to be compliant. So we need vcl to backport these features to old compilers on the trailing edge. I don't see that process ending anytime soon. Someday we will want the features from C++1x or C++2x. > So I would not move towards a vcl:: situation, but rather see > if we indeed are arriving at the point where "vcl_" can be > gradually replaced by "std::" > (and "#include <vcl_FOO.h>" by "#include <FOO>"). > > This way the v*l libraries will have a more "standard" look and > hence will be more easily usable within many C++ projects. > (The whole "vcl_" business has been frightening some people to use > vxl!) Even with my above comment, I agree with you here. I would love to see vcl go away. Maybe vcl should also work as a moving window. Maybe we should start to drop vcl_ in favor of std:: for the oldest and most standard parts of the STL. Some of the most commonly used parts of vcl are things like string and vector. Are we supporting and compilers that don't get these right? How many of our compilers do something other than define vcl_string to std::string? We could start phasing out vcl in most places, but continue to use it for exceptional cases where at least one compiler is not compliant. We would also continue to use it for new parts of the language that have not fully trickled down yet. What does everyone think about this? My hunch is that the vast majority of the VXL code could drop vcl entirely. The downside here is that we would have a mix of stl and vcl, and the dividing line might not always be clear. Matt |
From: Ian S. <ian...@st...> - 2008-04-04 07:50:35
|
Peter Vanroose wrote: > Actually, the whole point of vcl, from its perception on, was that > it should gradually vanish as time passes and std:: gets fully > adopted by all compilers we care for. > This way the v*l libraries will have a more "standard" look and > hence will be more easily usable within many C++ projects. > (The whole "vcl_" business has been frightening some people to use > vxl!) > I had this view as well. I was hoping we could soon convert vcl_ to std::. Most compilers are relatively compliant now. However the introduction of tr1 and C++0x will make vcl very useful again as the different compilers will take some time to bring their libraries and their languages up to the new standard. Much though I would like to see vcl go, and reduce the barriers to others using VXL, I am more concerned that our own code works properly on several platforms. Ian. |
From: Brendan M. <bre...@gm...> - 2008-04-07 02:05:31
|
On 04/04/2008, Ian Scott <ian...@st...> wrote: > Peter Vanroose wrote: > > Actually, the whole point of vcl, from its perception on, was that > > it should gradually vanish as time passes and std:: gets fully > > adopted by all compilers we care for. > > > > This way the v*l libraries will have a more "standard" look and > > hence will be more easily usable within many C++ projects. > > (The whole "vcl_" business has been frightening some people to use > > vxl!) > > > > > I had this view as well. I was hoping we could soon convert vcl_ to > std::. Most compilers are relatively compliant now. However the > introduction of tr1 and C++0x will make vcl very useful again as the > different compilers will take some time to bring their libraries and > their languages up to the new standard. > > Much though I would like to see vcl go, and reduce the barriers to > others using VXL, I am more concerned that our own code works properly > on several platforms. I too would like to see vcl fade into the background if at all possible. I think it affects vxl's credibility a bit to include things like vcl_string, vcl_stdout, vcl_endl etc. Worse, using vcl_ rather than vcl:: makes vcl look like it's not up with current compilers. I like Matt's idea - use std:: where it really is standard, and use vcl_ where it isn't (or vcl::). Although, for backwards compatibility, we'd probably want to be keeping the old vcl_ definitions around which leaves us in the same situation we are now - or does it give some advantages? -- Cheers, Brendan |
From: Amitha P. <ami...@us...> - 2008-04-03 21:19:59
|
Matt Leotta wrote: > A. I have no problem with introducing new symbols from C++0x into vcl > without hesitation. However, I am concerned about where these new > symbols can be used in VXL. Maybe we need another > "not-in-core-for-now" restriction. We can't just start replacing > vbl_smart_ptr with vcl_shared_ptr if the shared_ptr is only supported > on a few platforms. Or are you suggesting that we can use them > anywhere as long as we provided an ifdef'ed non-C++0x alternative? I was thinking more like implementing it as widely as possible, pinging vxl-maintainers on "is this wide enough", and then if there is consensus, use it without care. If there isn't consensus, then use it with a #ifdef check if you want. (See also my comments below.) > B. I agree that we shouldn't have an ENABLE_CXX0X option once we have > the vcl infrastructure for handling C++0x in place. When we have a > working solution for bringing together std and std::tr1, it can go. Agreed. > C. I think vcl features will have to be implemented on a best effort > basis. [...] We could write striped down versions that are not thread safe, but > that seems to defeat the purpose of moving to the C++0x shared_ptr. I think the best option is to provide the system ones where available, and a boost implementation otherwise, and roll our own cheap implementation only if we have to. Take a smart pointer, for example. I'd hate vcl_smart_ptr to be "not widely implemented" just because a clean, thread safe version isn't available for Borland 5.5. There are many places a smart pointer could be useful without having threads around. With a caveat in place that there are no guarantees that the cheapo implementation (e.g. vbl_smart_ptr) works with threads, Borland users can still use vcl_shared_ptr. Of course, I mean all this as a prior for making the decision. The posterior will depend on the individual function being discussed. Amitha. |
From: Matt L. <mat...@gm...> - 2008-04-03 22:39:53
|
On Thu, Apr 3, 2008 at 5:19 PM, Amitha Perera <ami...@us...> wrote: > I think the best option is to provide the system ones where available, and > a boost implementation otherwise, and roll our own cheap implementation only > if we have to. I think we may have to bring in a rather large chunck of Boost just to use the Boost shared_ptr. This brings back up the discussion of how much of boost to bring into vcl. What if Boost was an optional 3rd party library? That is, we used a native shared_ptr (or tr1::shared_ptr) if available. If not, we prompt the user to provide a path to Boost and then define vcl_shared_ptr to boost::shared_ptr. If Boost is not available, then we fall back on either a simple thread-unsafe implementation or require a workaround wherever vcl_shared_ptr is needed. What do you think? Matt |