
Rene Rivera <grafik.list@redshift-software.com> writes:
David Abrahams wrote:
Rene Rivera <grafik.list@redshift-software.com> writes:
Consider the usage you're proposing when you /do/ want a reference to bind to the actual argument:
typename binding<Args,tag::k,int>::type const& x = args[k | 0]
If the "k" argument wasn't supplied, your int const& will be a dangling reference.
OK I see it now :-) But it still doesn't change my POV. Here's my perspective with regards to the various use cases, when using defaults since my initial examples did not use defaults:
1. Most of the time I want, and expect, copies.
Okay. I'm not sure why, but that may not matter. What matters is that it's _your_ desire and expectation. Do we have any reason to think others will feel the same way? I have no problem with adding a value_binding<> template that does what you want, but so far I don't see why we should change binding<> itself.
And many times this is easy because on just writes out some preset type and assign:
int i = args[something | 1];
But that use case doesn't, to me, equate to the use case when it's not a fixed type:
typedef remove_reference<remove_const<binding<...>::type>::type T; T i = args[something | T(1)];
What do you mean by "equate?" Are you just saying, "it isn't so easy in that case?" You know, you can always write this once: template <class A, class K, class D = void> struct my_binding : remove_const< typename remove_reference< typename binding<A,K,D>::type >::type > {};
2. If I'm going to the trouble of getting the reference instead of the value. I'm also going to go the extra effort to not get a dangling reference as I would have even if I wasn't using boost::parameter:
int default_i = 0; int const & i = args[something | default_i];
That doesn't seem like a good enough reason to make binding<> that much more unsafe.
Which also doesn't equate to the case of a variable type:
typedef remove_reference<remove_const<binding<...>::type>::type T; T detault_i(0); T const & i = args[something | default_i];
3. I can see why having the binding type be a reference would signal some forms of dangling refs:
typedef binding<...>::type T; T i = args[something | T()]; // error
Huh? What error? And what is signalled?
But that seems like a mistake one would make because one is expecting the binding type to be the value_type.
I'm lost
4. And last, I can't remove_reference< remove_const<X> > on some types. In particular last week I was trying to pass in a member function pointer. Which the remove_* functions don't work on, or at least they don't after boost::parameter adds the "const &".
That should be fixed, then! But are you sure your problem isn't that you have the remove_ functions inside-out? remove_reference<remove_const<binding<...>::type>::type That will only remove reference-ness, but not constness, from a reference-to-const. The following compiles just fine for me, FWIW (g++-3.4.4): #include <boost/mpl/assert.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/remove_const.hpp> #include <boost/type_traits/remove_reference.hpp> struct X { int g(); }; template <class T> int f(T const& x) { using namespace boost; typedef T const& tcr; BOOST_MPL_ASSERT(( is_same< typename remove_const< typename remove_reference< tcr >::type >::type , T>)); return 0; } int x = f(&X::g); But if I invert the const and reference, of course it fails.
So I ended up having to use a boost::function instead.
??
Basically it seems like I end up having to jump through hoops in many use cases just to gain that compiler error on 1 use case and the default value_type in 1 other use case. Maybe I'm just weird and I would see things differently if I used things like the macros and forwarding functions.
Sorry, I'm totally lost. -- Dave Abrahams Boost Consulting www.boost-consulting.com