This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[c++0x] result_of
- From: "Jonathan Wakely" <jwakely dot gcc at gmail dot com>
- To: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Thu, 18 Sep 2008 23:36:17 +0100
- Subject: [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;
+}