|
View:
New views
9 Messages
—
Rating Filter:
Alert me
|
|
|
[c++0x] result_ofre 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 [result_of.20080918.patch] 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; +} |
|
|
Re: [c++0x] result_ofHi Jonathan,
and sorry about the delay, wanted to review some background material before answering... On Sep 19, 2008, at 12:36 AM, Jonathan Wakely wrote: > 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.) To be clear, the usual policy: we want the TR1 facilities to be essentially frozen. Certainly we don't want to update / extend the TR1 facilities to deal "correctly" with newer components, objects, etc, specified in the C++0x draft. TR1 must be consistent with C++03 and only with C++03. For the C++0x facilities we can afford to take (limited ;) risks, consistently with the experimental nature of the C+ +0x switch itself. That said, I always suggest proceeding in a stepwise way as much as possible: in a first installment of new facilities better not covering some special cases in new clauses and play safe with the rest of the library. > 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! :-) I think the patch is Ok as-is to close the PR. But please, try to follow the iter of the issues which you posted on the reflector and the following resolutions: eventually we don't want #if 0 blocks in the code delivered as part of gcc4.4.0, much better making a well thought choice and in a comment providing pointers to people willing to further investigate the options. Even more so for C++0x material. Thanks again, Paolo. |
|
|
Re: [c++0x] result_ofOn Tue, Sep 30, 2008 at 12:48 PM, Paolo Carlini
<paolo.carlini@...> wrote: > Hi Jonathan, > > and sorry about the delay, wanted to review some background material before > answering... > > On Sep 19, 2008, at 12:36 AM, Jonathan Wakely wrote: > >> 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.) > >> 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! :-) This is purely aesthetic, but I noticed that _S_fwd_arg() in _Result_of_util doesn't depend on the _Callee type and hence could in theory be moved into the 2 _Result_of_impl classes which would avoid the need for the template keyword to access it through _Result_of_util (unless I'm missing something, I admit I haven't tried it...). A small bit of code duplication to improve readability. Then again, often in c++, where one sees "ugly", others see "elegance" ;). Either way. Cheers, Chris |
|
|
Re: [c++0x] result_of2008/9/30 Chris Fairles:
> > This is purely aesthetic, but I noticed that _S_fwd_arg() in > _Result_of_util doesn't depend on the _Callee type and hence could in > theory be moved into the 2 _Result_of_impl classes which would avoid > the need for the template keyword to access it through _Result_of_util the ugly template keyword is necessary because _S_fwd_arg() itself is a function template, not because it's a member of a class template. Moving it to the impl classes would duplicate it, without getting rid of the template keyword. Thanks for looking over the patch though, I was wondering if anyone had seen it ;-) Jon |
|
|
Re: [c++0x] result_of2008/9/30 Paolo Carlini:
> On Sep 19, 2008, at 12:36 AM, Jonathan Wakely wrote: > >> 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.) > > To be clear, the usual policy: we want the TR1 facilities to be essentially > frozen. Certainly we don't want to update / extend the TR1 facilities to > deal "correctly" with newer components, objects, etc, specified in the C++0x > draft. TR1 must be consistent with C++03 and only with C++03. OK - there still might be C++03 components for which tr1::result_of doesn't work, but I can't think of any right now :-) C++0x's default_delete was the first example I found ... there might be no problems with the C++03 parts. >> 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! :-) > > I think the patch is Ok as-is to close the PR. But please, try to follow the > iter of the issues which you posted on the reflector and the following > resolutions: eventually we don't want #if 0 blocks in the code delivered as > part of gcc4.4.0, much better making a well thought choice and in a comment > providing pointers to people willing to further investigate the options. Agreed. The "reference type" issue will be LWG 904, I'll make sure the pointer-to-member issue is addressed too, either as part of 904 or separately. Thanks, Jon |
|
|
Re: [c++0x] result_ofHi Jonathan,
>> I think the patch is Ok as-is to close the PR. But please, try to follow the >> iter of the issues which you posted on the reflector and the following >> resolutions: eventually we don't want #if 0 blocks in the code delivered as >> part of gcc4.4.0, much better making a well thought choice and in a comment >> providing pointers to people willing to further investigate the options. >> > Agreed. The "reference type" issue will be LWG 904, I'll make sure > the pointer-to-member issue is addressed too, either as part of 904 or > separately. > > Earlier today I added the C++0x versions of the existing tr1::reference_wrapper tests + the testcase from libstdc++/24803 (which I assigned to myself, but only tentatively): while we are touching reference_wrapper too, we should make sure not to regress, and, if possible, we should also fix 24803 (the minimal version). Can you double check your existing patch vs the 3 additional testcases? And / or we can imagine splitting out the reference_wrapper changes... probably I'm Ok with any plan you may want to suggest... Just let me know... Thanks, Paolo. |
|
|
Re: [c++0x] result_of2008/10/5 Paolo Carlini:
> > Earlier today I added the C++0x versions of the existing > tr1::reference_wrapper tests + the testcase from libstdc++/24803 (which > I assigned to myself, but only tentatively): while we are touching > reference_wrapper too, we should make sure not to regress, and, if > possible, we should also fix 24803 (the minimal version). Can you double > check your existing patch vs the 3 additional testcases? And / or we can > imagine splitting out the reference_wrapper changes... probably I'm Ok > with any plan you may want to suggest... Just let me know... Thanks for CCing me on the other PRs, I'll review them and run the new testcases in the next couple of days and get back to you. Cheers, Jonathan |
|
|
Re: [c++0x] result_of2008/10/5 Jonathan Wakely:
> 2008/10/5 Paolo Carlini: >> >> Earlier today I added the C++0x versions of the existing >> tr1::reference_wrapper tests + the testcase from libstdc++/24803 (which >> I assigned to myself, but only tentatively): while we are touching >> reference_wrapper too, we should make sure not to regress, and, if >> possible, we should also fix 24803 (the minimal version). Can you double >> check your existing patch vs the 3 additional testcases? And / or we can >> imagine splitting out the reference_wrapper changes... probably I'm Ok >> with any plan you may want to suggest... Just let me know... > > Thanks for CCing me on the other PRs, I'll review them and run the new > testcases in the next couple of days and get back to you. My change causes regressions for the new tests, I've broken INVOKE() but I know what the problem is and it can be solved by the "bit of genius" in _Mem_fn. Jonathan |
|
|
Re: [c++0x] result_ofJonathan Wakely wrote:
> My change causes regressions for the new tests, I've broken INVOKE() > but I know what the problem is and it can be solved by the "bit of > genius" in _Mem_fn. > Ok, great. Please keep me updated... Thanks, Paolo. |
| Free Forum Powered by Nabble | Forum Help |