Boost logo

Boost Users :

Subject: Re: [Boost-users] Odd Warning in transform_iterator.hpp ?
From: Nathan Ridge (zeratul976_at_[hidden])
Date: 2011-07-28 05:50:15


----------------------------------------
> From: zeratul976_at_[hidden]
> To: boost-users_at_[hidden]
> Subject: RE: [Boost-users] Odd Warning in transform_iterator.hpp ?
> Date: Thu, 28 Jul 2011 09:10:30 +0000
>
>
> > I'm using the current Boost library on Microsoft Visual Studio 2005. I'm getting a
> > warning on line 121 of transform_iterator.hpp, complaining "returning address of local
> > variable or temporary". The line in question is the body of this function:
> >
> > typename super_t::reference dereference() const
> > { return m_f(*this->base()); }
> >
> > My m_f supplied to the template is ordinary enough; it returns a value.
>
> Is your m_f a function object that uses result_of protocol to declare
> its return value?
>
> It may be that while its operator() returns a value, its result<> is telling
> transform_iterator that it returns a reference.
>
> For example, if its result<> looks like this:
>
> template <typename> struct result;
> template <typename F, typename T>
> struct result<F(T)>
> {
> typedef T type;
> };
>
> then transform iterator will deduce its return type to be a reference:
>
> typedef typename ia_dflt_help<
> Reference
> , result_of<UnaryFunc(typename std::iterator_traits<Iterator>::reference)>
> >::type reference;
>
> and it will use this as the return type of operator*. Hence the warning.

Let me elaborate a bit more...
 
I've run into this problem before. The reason this behaviour is surprising
is that if your operator() looks like this:
 
template <typename T>
T operator()(T o)
{
   ...
}
 
then you would think that this result<> template describes it's behaviour
accurately:
 
template <typename> struct result;
template <typename F, typename T>
struct result<F(T)>
{
    typedef T type;
};

After all, the result<> just says "T in, T out", which is exactly what
the operator() does, right?
 
Not quite.
 
When you have a template function, such as
 
template <typename T>
T f(T o)
{
    ...
}
 
and you call it with an argument, such as
 
f(x)
 
the compiler performs a process called "template argument deduction".
This process involves looking at the function parameter types,
which are expressed in terms of the template parameters, matching
them up with the types of the passed arguments, and from this,
deducing the types of the template parameters.
 
In a simple case like this, where there is a single template parameter,
a single function parameter, and the type of the function parameter
is the template parameter verbatim, you might think that the deduction
is trivial, i.e. "T is deduced to be the type of x".
 
In actual fact, there is more than that going on behind the scenes.
Even in such a simple case, the compiler will perform certain
"transformations" to the type of x before coming up with T.
One of these transformations is removing references and const.
So, even if x has type "const int&", T will not be "const int&",
it will just be "int", and therefore the function will return "int".
 
Most users don't notice these transformations until their attention
is brought to them, and THIS IS GOOD. The intent of the transformations
is to make templates "just work" the way you intend them to. Without
these transformations, a simple template function like 'f' above
really would be returning a reference to a temporary in many cases,
and that is clearly not what anyone intends for it to do. Hence
the transformations.
 
However, if you explicitly specify the template parameters of a
tempate (whether function or class template), no trasformations
occur. For example, if you call f<const int&>(x), then T will be
"const int&", and the function will return "const int&".
 
Similarly, for the result<> metafunction above,
result<const int&>::type will be "const int&".
 
So even though result<> seems to be agreeing with operator()
exactly, it is not.
 
Yes, this is a PITA. In C++0x you will be able to use decltype
and avoid having to write such result<> metafunctions altogether.
Until then, I'm afraid we just have to put up with it...
 
Regards,
Nate.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net