arlo on 17 May 2003 05:05:01 -0000 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
Re: [ALACPP] Chris' stupid C++ trick of the week |
> It strikes me that the reference-to-reference problem is much less > likely to occur without a great deal of explicitness on the callers > part. That is the real source of my concern with the original problem: > the "surprise" factor. So, while you can create the problem you are > talking about with something on the order of: > > bar = doFoo<MyClass&>(baz); > > If you are going to explicitly instantiate template parameters on my > function, I expect you to understand how the template expands in a crazy > way. > > Whereas, if you just do: > > bar = doFoo(baz); > > I can't imagine types for baz and bar which would cause the compiler to > select the double reference case. <!-- Taken from the motivation for boost::call_traits --> Consider the definition of std::binder1st: template <class Operation> class binder1st : public unary_function<typename Operation::second_argument_type, typename Operation::result_type> { protected: Operation op; typename Operation::first_argument_type value; public: binder1st(const Operation& x, const typename Operation::first_argument_type& y); typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const; }; Now consider what happens in the relatively common case that the functor takes its second argument as a reference, that implies that Operation::second_argument_type is a reference type, operator() will now end up taking a reference to a reference as an argument, and that is not currently legal. The solution here is to modify operator() to use call_traits: typename Operation::result_type operator()(typename call_traits<typename Operation::second_argument_type>::param_type x) const; Now in the case that Operation::second_argument_type is a reference type, the argument is passed as a reference, and the no "reference to reference" occurs. <!-- End extracted code. --> Then, the code: class BazCompare : public std::binary_fucntion< int&, int&, bool > { // ... bool operator(int &a, int &b); }; first_baz = std::find_if(vec.begin(), vec.end(), std::bind_1st(BazCompare, 3)); would result in a reference to reference. The type computation engine for standard STL binding is one case where you can run into problems. There are others. However, almost all of them result from a) the function that you are declaring with a ref arg is a member of a templated class, and b) you are using template type deduction or type computation to determine the type to instantiate that class with. These are the sort of examples that come up a lot if you make active use of templates, and not much if you don't. I ran into it when I created my generic EventHandler. The boost people ran into it when they created generic boost::bind. Most functors have it (operator() can be a real source of issues). However, a lot of other code won't run into the problem. Really, your specific code may be safe, because it (probably) isn't a member function. However, if it is, then you need to be aware of the issue. After all, the other half of the problem comes at the use site, suprises the user, is difficult to track down, and can not always be easily fixed. The member function can always be successfully fixed with call_traits, if you can change the class, but the call site may use type deduction or type computation and require some additional traits mojo to repair. Arlo _______________________________________________ alacpp mailing list alacpp@xxxxxxxxxxx http://lists.ellipsis.cx/mailman/listinfo/alacpp