
on Thu Nov 13 2008, Eric Niebler <eric-AT-boost-consulting.com> wrote:
I've noticed test failures when compiling some of boost in C++0x mode due to the change to boost::result_of to use decltype. The problem comes from function objects like this:
template<class T> struct identity { typedef T result_type;
T const & // <== problem here operator()(T const &t) const { return t; } };
In this (overly simplistic) example, we just want to return what is passed in. The computed type (result_type) is different than the return type of operator() ... and for a good (IMO) reason: to avoid an unnecessary copy in some cases. The idea is to accommodate usage like this:
result_of<identity(BigObj)>::type i = identity()(BigObj()); You need a template argument here---------------^
It is really very important that decltype(i) be BigObj, and not BogObj const &, which would cause a dangling reference. But with the change to use decltype in boost::result_of, the dangling reference is exactly what I would get.
It seems like you're expecting the line above to act like auto i = identity<BigObj>()(BigObj()); but that's not what result_of is supposed to do. It is supposed to tells you, in excruciating detail, about the return type of the function call.
Am I now forced to change identity::operator() return by value here?
Either that or change your expectations about the right way to declare i.
That seems sub-optimal to me. In many other potential uses of identity (e.g., when forwarding the result to some other function), the copy is totally unnecessary.
Ah, well. The optimal safe way to write an identity function is of course template <class T> T identity(T x) { return boost::move(x); } which on any decent compiler should cause no copies provided T is move-enabled, and only one if it isn't. -- Dave Abrahams BoostPro Computing http://www.boostpro.com