This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ 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]

[c++0x] result_of


re libstdc++/37351

I had a go at updating result_of and reference_wrapper to match the
current WP, which raised the following points:

1) Implementations are permitted use special compiler hooks so that
tr1::result_of gives the right answer.
std::result_of must always give the right answer for a well-formed
expression, which can be done with decltype in 0x mode.

2) According to TR1 all function objects defined by the standard
library must give the right answer with tr1::result_of. Making that
work might require a result_type typedef or a result_of partial
specialisation to be added to some components outside the tr1 dir e.g.
std::default_delete (or tr1::result_of could use decltype too.)

3) If the expression is ill-formed, tr1::result_of should still give
an answer in some cases, such as when there is a nested result_type
typedef. N2723 has no such requirement, so I take that to mean
std::result_of should reject ill-formed expressions.

I think the compiler should reject this:

   struct X { };
   typename int (X::*MemFun)();
   result_of< MemFun(X*) >::type i;

because it's not valid to use a pointer-to-member with that syntax
(see n1695 for an interesting proposal to allow it.)

This requirement is easy to implement (just remove tr1::result_of's
special handling for pointer-to-member types) but that breaks
reference_wrapper::operator() and __invoke(), so I made std::result_of
handle pointer-to-member types.  I have asked on the reflector whether
result_of should handle pointers to members.  If it shouldn't, it will
be possible to make result_of reject them, while providing an enhanced
version that does support them and can be used internally.

4) N2723 and TR1 have the same text regarding the arguments types:

"The values ti are lvalues when the corresponding type Ti is a
reference type, and rvalues otherwise."

This might need to be updated with respect to rvalue-references,
otherwise this will compile:

  typedef int (*func)(int&);
  result_of<func(int&&)>::type i = 0;

even though this is not valid:

  int f(int&);
  f( std::move(0) );

I raised this on the lib reflector and suggested the text should be
"The values ti are lvalues when the corresponding type Ti is an
lvalue-reference type" and that is what this patch does, see
_Result_of_util::_S_fwd_arg()

The _S_fwd_* functions in _Result_of_util and _Result_of_impl are
never called, only their return types are needed by the decltype
expressions.

This probably isn't ready to go in, but here's a patch for discussion.
If I've missed an obvious way to do it better please point it out! :-)

Jonathan

WP http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2723.pdf
TR1 http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1836.pdf
n1695 http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1695.html
n1454 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1454.html
Index: include/tr1_impl/functional
===================================================================
--- include/tr1_impl/functional	(revision 140475)
+++ include/tr1_impl/functional	(working copy)
@@ -153,6 +153,7 @@
   template<typename _Signature>
     class result_of;
 
+#ifdef _GLIBCXX_INCLUDE_AS_TR1
   /**
    *  Actual implementation of result_of. When _Has_result_type is
    *  true, gets its result from _Weak_result_type. Otherwise, uses
@@ -210,6 +211,93 @@
       typedef void type;
     };
 
+#else
+  /**
+   *  Actual implementation of std::result_of.
+  */
+  template<bool _Is_mem_obj_ptr, bool _Is_mem_fun_ptr, typename _Signature>
+    struct _Result_of_impl;
+
+  // Helper functions used by _Result_of_impl.
+  template<typename _Callee>
+    class _Result_of_util
+    {
+    protected:
+      // get lvalue- or rvalue-reference lhs to use in (lhs.*memptr)
+      static typename conditional<
+        is_pointer<_Callee>::value,
+        typename add_lvalue_reference<
+          typename remove_pointer<_Callee>::type>::type,
+        typename add_rvalue_reference<_Callee>::type>::type
+      _S_fwd_lhs();
+
+      // N2723 requires "reference types" to be treated as lvalues,
+      // but that gives the wrong result for rvalue reference types.
+#if 0
+      template<typename _ArgT>
+        static typename conditional<is_reference<_ArgT>::value,
+          typename add_lvalue_reference<_ArgT>::type,
+          typename add_rvalue_reference<_ArgT>::type>::type
+        _S_fwd_arg();
+#else
+      template<typename _ArgT>
+        static typename add_rvalue_reference<_ArgT>::type
+        _S_fwd_arg();
+#endif
+    };
+
+  // Handle member data pointers.
+  template<typename _Res, typename _Class, typename _T1>
+    class _Result_of_impl<true, false, _Res _Class::*(_T1)>
+    : public _Result_of_util<_T1>
+    {
+      typedef _Res _Class::*_MemPtr;
+    public:
+      typedef decltype(
+          (_Result_of_util<_T1>::_S_fwd_lhs().*(_MemPtr()))
+          ) type;
+    };
+
+  // Handle member function pointers.
+  template<typename _MemFun, typename _T1, typename... _ArgTypes>
+    struct _Result_of_impl<false, true, _MemFun(_T1, _ArgTypes...)>
+    : public _Result_of_util<_T1>
+    {
+      typedef decltype(
+          (_Result_of_util<_T1>::_S_fwd_lhs().*(_MemFun())) (
+            _Result_of_util<_T1>::template _S_fwd_arg<_ArgTypes>() ... ) ) type;
+    };
+
+  // Handle other callable types.
+  template<typename _Functor, typename... _ArgTypes>
+    struct _Result_of_impl<false, false, _Functor(_ArgTypes...)>
+    : public _Result_of_util<bool>
+    {
+      // get an example of the callable type
+#if 0
+      static typename add_rvalue_reference<_Functor>::type
+#else
+      static typename conditional<
+        is_function<typename remove_reference<_Functor>::type>::value,
+        typename add_pointer<_Functor>::type,
+        typename add_rvalue_reference<_Functor>::type>::type
+#endif
+      _S_fwd_functor();
+
+      typedef decltype( _Result_of_impl::_S_fwd_functor() (
+            _Result_of_util<bool>::template _S_fwd_arg<_ArgTypes>() ... ) ) type;
+    };
+
+  template<typename _Functor, typename... _ArgTypes>
+    class result_of<_Functor(_ArgTypes...)>
+    : public _Result_of_impl<
+      is_member_object_pointer<_Functor>::value,
+      is_member_function_pointer<_Functor>::value,
+      _Functor(_ArgTypes...)>
+    {
+    };
+#endif
+
   /// Determines if the type _Tp derives from unary_function.
   template<typename _Tp>
     struct _Derives_from_unary_function : __sfinae_types
@@ -255,6 +343,7 @@
       typedef _Tp* type;
     };
 
+#ifdef _GLIBCXX_INCLUDE_AS_TR1
   /**
    * Invoke a function object, which may be either a member pointer or a
    * function object. The first parameter will tell which.
@@ -297,7 +386,51 @@
     {
       return __f(__args...);
     }
+#else
+  /**
+   * Invoke a function object, which may be either a member pointer or a
+   * function object. The first parameter will tell which.
+   */
+  template<typename _Functor, typename... _Args>
+    inline
+    typename enable_if<
+             (!is_member_pointer<_Functor>::value
+              && !is_function<_Functor>::value
+              && !is_function<typename remove_pointer<_Functor>::type>::value),
+             typename result_of<_Functor(_Args...)>::type
+           >::type
+    __invoke(_Functor& __f, _Args&&... __args)
+    {
+      return __f(std::forward<_Args>(__args)...);
+    }
 
+  template<typename _Functor, typename... _Args>
+    inline
+    typename enable_if<
+             (is_member_pointer<_Functor>::value
+              && !is_function<_Functor>::value
+              && !is_function<typename remove_pointer<_Functor>::type>::value),
+             typename result_of<_Functor(_Args...)>::type
+           >::type
+    __invoke(_Functor& __f, _Args&&... __args)
+    {
+      return mem_fn(__f)(std::forward<_Args>(__args)...);
+    }
+
+  // To pick up function references (that will become function pointers)
+  template<typename _Functor, typename... _Args>
+    inline
+    typename enable_if<
+             (is_pointer<_Functor>::value
+              && is_function<typename remove_pointer<_Functor>::type>::value),
+             typename result_of<_Functor(_Args...)>::type
+           >::type
+    __invoke(_Functor __f, _Args&&... __args)
+    {
+      return __f(std::forward<_Args>(__args)...);
+    }
+#endif
+
   /**
    *  Knowing which of unary_function and binary_function _Tp derives
    *  from, derives from the same and ensures that reference_wrapper
@@ -440,10 +573,18 @@
     public:
       typedef _Tp type;
 
+#ifdef _GLIBCXX_INCLUDE_AS_TR1
       explicit
       reference_wrapper(_Tp& __indata): _M_data(&__indata)
       { }
+#else
+      reference_wrapper(_Tp& __indata): _M_data(&__indata)
+      { }
 
+      explicit
+      reference_wrapper(_Tp&&) = delete;
+#endif
+
       reference_wrapper(const reference_wrapper<_Tp>& __inref):
       _M_data(__inref._M_data)
       { }
@@ -462,12 +603,21 @@
       get() const
       { return *_M_data; }
 
+#ifdef _GLIBCXX_INCLUDE_AS_TR1
       template<typename... _Args>
         typename result_of<_M_func_type(_Args...)>::type
         operator()(_Args&... __args) const
         {
 	  return __invoke(get(), __args...);
 	}
+#else
+      template<typename... _Args>
+        typename result_of<_Tp(_Args...)>::type
+        operator()(_Args&&... __args) const
+        {
+	  return __invoke(get(), std::forward<_Args>(__args)...);
+	}
+#endif
     };
 
 
Index: testsuite/20_util/function_objects/return_types/result_of_neg.cc
===================================================================
--- testsuite/20_util/function_objects/return_types/result_of_neg.cc	(revision 0)
+++ testsuite/20_util/function_objects/return_types/result_of_neg.cc	(revision 0)
@@ -0,0 +1,51 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING.  If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// 20.6.4 function object return types [func.ret]
+#include <functional>
+#include <testsuite_hooks.h>
+
+struct X
+{
+    int i;
+    int f();
+};
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  using std::result_of;
+  using std::is_same;
+
+  typedef int X::*pm;
+  typedef int (X::*pmf)();
+  typedef int (*pf)();
+
+  result_of<pf(int)>::type test3; // { dg-error "here" }
+  // { dg-error "too many arguments to function" "" { target *-*-* } 288 }
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
+// { dg-excess-errors "" }
Index: testsuite/20_util/function_objects/return_types/result_of_ref.cc
===================================================================
--- testsuite/20_util/function_objects/return_types/result_of_ref.cc	(revision 0)
+++ testsuite/20_util/function_objects/return_types/result_of_ref.cc	(revision 0)
@@ -0,0 +1,50 @@
+// { dg-options "-std=gnu++0x" }
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING.  If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// 20.6.4 function object return types [func.ret]
+#include <functional>
+#include <testsuite_hooks.h>
+
+struct X
+{
+    int operator()(int&);
+    float operator()(int&&);
+};
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  using std::result_of;
+  using std::is_same;
+
+  typedef int (*func_ptr)(int&);
+
+  VERIFY((is_same<result_of<X(int)>::type, float>::value));
+  VERIFY((is_same<result_of<X(int&)>::type, int>::value));
+  // VERIFY((is_same<result_of<X(int&&)>::type, int>::value));
+  VERIFY((is_same<result_of<X(int&&)>::type, float>::value));
+  VERIFY((is_same<result_of<func_ptr(int&)>::type, int>::value));
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
Index: testsuite/20_util/function_objects/return_types/result_of.cc
===================================================================
--- testsuite/20_util/function_objects/return_types/result_of.cc	(revision 0)
+++ testsuite/20_util/function_objects/return_types/result_of.cc	(revision 0)
@@ -0,0 +1,76 @@
+// { dg-options "-std=gnu++0x" }
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING.  If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// 20.6.4 function object return types [func.ret]
+#include <functional>
+#include <testsuite_hooks.h>
+
+struct nested_result_type
+{
+    typedef float result_type;
+    int operator()();
+};
+
+struct nested_result_template
+{
+  template<typename F> struct result { typedef float type; };
+  int operator()(int);
+};
+
+struct cv_overload
+{
+  int operator()(int);
+  char operator()(char) const;
+  float operator()(float) volatile;
+};
+
+struct default_args
+{
+    int operator()(int* = 0, int* = 0);
+    void operator()(void*);
+};
+
+class X {};
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  using std::result_of;
+  using std::is_same;
+
+  typedef int (*func_ptr)(float, double);
+  typedef int (&func_ref)(float, double);
+
+  VERIFY((is_same<result_of<nested_result_type()>::type, int>::value));
+  VERIFY((is_same<result_of<nested_result_template(int)>::type, int>::value));
+  VERIFY((is_same<result_of<cv_overload(int)>::type, int>::value));
+  VERIFY((is_same<result_of<const cv_overload(int)>::type, char>::value));
+  VERIFY((is_same<result_of<volatile cv_overload(int)>::type, float>::value));
+  VERIFY((is_same<result_of<default_args(int*)>::type, int>::value));
+  VERIFY((is_same<result_of<default_args(char*)>::type, void>::value));
+  VERIFY((is_same<result_of<func_ptr(char, float)>::type, int>::value));
+  VERIFY((is_same<result_of<func_ref(char, float)>::type, int>::value));
+}
+
+int main()
+{
+  test01();
+  return 0;
+}

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