This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libstdc++/24803] tr1::reference_wrapper and pointers to member functions

------- 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());


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]