This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug libstdc++/24803] tr1::reference_wrapper and pointers to member functions
- From: "doug dot gregor at gmail dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 12 Nov 2005 13:23:16 -0000
- Subject: [Bug libstdc++/24803] tr1::reference_wrapper and pointers to member functions
- References: <bug-24803-3433@http.gcc.gnu.org/bugzilla/>
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
------- Comment #2 from doug dot gregor at gmail dot com 2005-11-12 13:23 -------
I don't know how to classify this. The basic problem is one that isn't
really solveable without rvalue references: you can't pass a literal
(e.g., 0) into the operator() of a reference_wrapper or any other
function object in TR1, because the arguments are accepted by
T&. Strictly speaking, this is not a bug.
However, there are several ways that we could make this work, because
John is doing some very sensible things here [*]. Some ideas are:
(1) Strong-arm a C++ front-end guru into implementing rvalue references,
then use them in the TR1 function objects. Heck, we'll need 'em
for C++0x anyway :)
(2) When we know the argument types (e.g., when the T in reference_wrapper<T>
is a function pointer, member function pointer, or class that is derived
from unary_function or binary_function), we could inject operator()
overloads that have precise type signatures, e.g.,
T::result_type operator()(T::argument_type const&);
That's really messy and would require quite a bit of refactoring in
reference_wrapper to get right.
(3) Provide variants of operator() that accept "const T&" arguments in
addition to those that accept "T&" arguments. This makes
bind/mem_fn/reference_wrapper easier to use, but the number of overloads
blows up exponentially. Since we've already run into compilation time
issues, we'd have stop doing this once we hit four to five
arguments (then we get the "I just added one more argument and
everything blew up!" bug reports).
(4) Strong-arm a C++ front-end guru into allowing the conversion
operator (operator T&() const) to actually work for function
call expressions, making most of reference_wrapper<T>::operator()
magically go away. (Peter Dimov has suggested this before, but
it hasn't really worked its way through the committee).
(1) is the forward-looking solution; (2) and (3) are hacks that could
make the code even uglier (ick!). (4) only fixes the problem for
reference_wrapper. At this point, I favor (1) strongly, but I'm not in
a position to strong-arm nor am I in a position to implement rvalue
references myself.
[*] One thing in the code that perhaps shouldn't work is passing the
literal 0 as the argument to
reference_wrapper<int (test_type::*)()>::operator()
That means that we need to be able to realize that it's a literal 0
(tricky, messy, but doable; see the construction-from-literal-zero
trick in tr1::function<>) and then convert that to a NULL test_type*.
I don't think John meant to test that, and I don't really think we
should care if it's broken.
A slightly simplified version of John's test case that does work
properly follows. Replace any of null_tt, null_ttc, or zero in the
calls to reference_wrapper objects to trigger compiler errors.
#include <tr1/functional>
struct test_type
{
int member();
int cmember()const;
int member2(char);
int cmember2(char)const;
};
struct functor1 : public std::unary_function<int, double>
{
double operator()(int)const;
};
struct functor2 : public std::binary_function<int, char, double>
{
double operator()(int, char)const;
};
template <class T>
void verify_return_type(T, T)
{
}
int main()
{
test_type* null_tt = 0;
const test_type* null_ttc = 0;
int zero;
std::tr1::reference_wrapper<double (int)>* pr1;
verify_return_type((*pr1)(0), double());
std::tr1::reference_wrapper<double (*)(int)>* pr2;
verify_return_type((*pr2)(0), double());
std::tr1::reference_wrapper<int (test_type::*)()>* pr3;
verify_return_type((*pr3)(null_tt), int());
std::tr1::reference_wrapper<int (test_type::*)()const>* pr4;
verify_return_type((*pr4)(null_ttc), int());
std::tr1::reference_wrapper<functor1>* pr5;
verify_return_type((*pr5)(zero), double());
std::tr1::reference_wrapper<double (int, char)>* pr1b;
verify_return_type((*pr1b)(0,0), double());
std::tr1::reference_wrapper<double (*)(int, char)>* pr2b;
verify_return_type((*pr2b)(0,0), double());
std::tr1::reference_wrapper<int (test_type::*)(char)>* pr3b;
verify_return_type((*pr3b)(null_tt,zero), int());
std::tr1::reference_wrapper<int (test_type::*)()const>* pr4b;
verify_return_type((*pr4b)(null_ttc), int());
std::tr1::reference_wrapper<functor2>* pr5b;
verify_return_type((*pr5b)(zero,zero), double());
}
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24803