----------------------------------------
From: zeratul976@hotmail.com
To: boost-users@lists.boost.org
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
struct result
{
typedef T type;
};
then transform iterator will deduce its return type to be a reference:
typedef typename ia_dflt_help<
Reference
, result_of
::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
struct result
{
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(x), then T will be
"const int&", and the function will return "const int&".
Similarly, for the result<> metafunction above,
result::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.