diff mbox

[v3] plus<void>

Message ID alpine.DEB.2.02.1309250025470.25959@stedding.saclay.inria.fr
State New
Headers show

Commit Message

Marc Glisse Sept. 24, 2013, 10:37 p.m. UTC
Hello,

this was only minimally tested since trunk is broken at the moment. There 
don't seem to be specific tests for the existing functors, so a couple 
tests for the new specializations seem good enough.

2013-09-25  Marc Glisse  <marc.glisse@inria.fr>

 	* include/bits/stl_function.h: Include <bits/move.h> for std::forward.
 	(bit_not): New class.
 	(plus<void>, minus<void> ,multiplies<void>, divides<void>,
 	modulus<void>, negate<void>, equal_to<void>, not_equal_to<void>,
 	greater<void>, less<void>, greater_equal<void>, less_equal<void>,
 	logical_and<void>, logical_or<void>, logical_not<void>, bit_and<void>,
 	bit_or<void>, bit_xor<void>, bit_not<void>): New specializations.
 	* testsuite/20_util/headers/functional/generic_function_objects.cc:
 	New file.

Comments

Paolo Carlini Sept. 24, 2013, 10:47 p.m. UTC | #1
On 9/24/13 5:37 PM, Marc Glisse wrote:
> Hello,
>
> this was only minimally tested since trunk is broken at the moment. 
> There don't seem to be specific tests for the existing functors, so a 
> couple tests for the new specializations seem good enough.
What about at least covering all of them? Just to make sure that 
instantiating the member template operators works, at definition time 
the front-end doesn't check much.

Paolo.
Jonathan Wakely Sept. 24, 2013, 11:34 p.m. UTC | #2
On 24 September 2013 23:37, Marc Glisse wrote:
> Hello,
>
> this was only minimally tested since trunk is broken at the moment. There
> don't seem to be specific tests for the existing functors, so a couple tests
> for the new specializations seem good enough.
>

I've had this sitting in my tree waiting to do something with, I'm
about to go to sleep so didn't check if the test covers anything yours
doesn't.

It looks like your patch adds the default template argument even in
C++98 mode, I avoided that by putting forward declarations at the top
of the file, in a #if block.

I used an incomplete __is_transparent type, but void works just as well.
Marc Glisse Sept. 25, 2013, 5:41 a.m. UTC | #3
On Wed, 25 Sep 2013, Jonathan Wakely wrote:

> I've had this sitting in my tree waiting to do something with,

I did ask last week if someone had done it already...

> I'm about to go to sleep so didn't check if the test covers anything 
> yours doesn't.

In the test you have basic cover for all functors, and I cover only 2 
cases (more specifically though, since I look at the return type cv-qual).

In my patch, I added constexpr and noexcept, I couldn't see any reason not 
to for such basic utilities. Yes, I did read the wiki and noticed the vote 
yesterday about constexpr, but imho that's wrong.

> It looks like your patch adds the default template argument even in
> C++98 mode, I avoided that by putting forward declarations at the top
> of the file, in a #if block.

This only lets me write:
std::plus<> *p;
in C++98 mode (std::plus<> p; gives an error), doesn't seem that bad.

And I also add the void specializations in C++11 mode, as an extension.

Well, let's forget my patch and go with yours, though at least adding 
noexcept seems like a good idea.

(too bad we don't have noexcept(auto) here)
(too bad we can't use decltype(auto) for the return type, as that would 
disable sfinae, it is a bad sign when the standard turns its nose up at 
its own dog food...)
Jonathan Wakely Sept. 25, 2013, 8:07 a.m. UTC | #4
On 25 September 2013 06:41, Marc Glisse wrote:
> On Wed, 25 Sep 2013, Jonathan Wakely wrote:
>
>> I've had this sitting in my tree waiting to do something with,
>
>
> I did ask last week if someone had done it already...

Sorry :-\

>
>> I'm about to go to sleep so didn't check if the test covers anything yours
>> doesn't.
>
>
> In the test you have basic cover for all functors, and I cover only 2 cases
> (more specifically though, since I look at the return type cv-qual).
>
> In my patch, I added constexpr and noexcept, I couldn't see any reason not
> to for such basic utilities. Yes, I did read the wiki and noticed the vote
> yesterday about constexpr, but imho that's wrong.
>
>
>> It looks like your patch adds the default template argument even in
>> C++98 mode, I avoided that by putting forward declarations at the top
>> of the file, in a #if block.
>
>
> This only lets me write:
> std::plus<> *p;
> in C++98 mode (std::plus<> p; gives an error), doesn't seem that bad.
>
> And I also add the void specializations in C++11 mode, as an extension.
>
> Well, let's forget my patch and go with yours, though at least adding
> noexcept seems like a good idea.

Yes, noexcept is a good idea.

> (too bad we don't have noexcept(auto) here)
> (too bad we can't use decltype(auto) for the return type, as that would
> disable sfinae, it is a bad sign when the standard turns its nose up at its
> own dog food...)

Yeah, I think the idea is that concepts will make SFINAE a thing of
the past, but we're not there yet.
diff mbox

Patch

Index: include/bits/stl_function.h
===================================================================
--- include/bits/stl_function.h	(revision 202872)
+++ include/bits/stl_function.h	(working copy)
@@ -49,20 +49,22 @@ 
  */
 
 /** @file bits/stl_function.h
  *  This is an internal header file, included by other library headers.
  *  Do not attempt to use it directly. @headername{functional}
  */
 
 #ifndef _STL_FUNCTION_H
 #define _STL_FUNCTION_H 1
 
+#include <bits/move.h> // for std::forward
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // 20.3.1 base classes
   /** @defgroup functors Function Objects
    * @ingroup utilities
    *
    *  Function objects, or @e functors, are objects with an @c operator()
    *  defined and accessible.  They can be passed as arguments to algorithm
@@ -129,201 +131,514 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
    * @ingroup functors
    *
    *  Because basic math often needs to be done during an algorithm,
    *  the library provides functors for those operations.  See the
    *  documentation for @link functors the base classes@endlink
    *  for examples of their use.
    *
    *  @{
    */
   /// One of the @link arithmetic_functors math functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct plus : public binary_function<_Tp, _Tp, _Tp>
     {
       _Tp
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x + __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct plus<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) + std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) + std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) + std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link arithmetic_functors math functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct minus : public binary_function<_Tp, _Tp, _Tp>
     {
       _Tp
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x - __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct minus<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) - std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) - std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) - std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link arithmetic_functors math functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct multiplies : public binary_function<_Tp, _Tp, _Tp>
     {
       _Tp
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x * __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct multiplies<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) * std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) * std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) * std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link arithmetic_functors math functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct divides : public binary_function<_Tp, _Tp, _Tp>
     {
       _Tp
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x / __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct divides<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) / std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) / std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) / std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link arithmetic_functors math functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct modulus : public binary_function<_Tp, _Tp, _Tp>
     {
       _Tp
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x % __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct modulus<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) % std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) % std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) % std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link arithmetic_functors math functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct negate : public unary_function<_Tp, _Tp>
     {
       _Tp
       operator()(const _Tp& __x) const
       { return -__x; }
     };
+
+#if __cplusplus >= 201103L
+  template<>
+    struct negate<void>
+    {
+      template <class _Tp>
+      constexpr auto
+      operator()(_Tp&& __x) const
+      noexcept(noexcept(-std::forward<_Tp>(__x)))
+      -> decltype(-std::forward<_Tp>(__x))
+      {
+	return -std::forward<_Tp>(__x);
+      }
+      typedef void is_transparent;
+  };
+#endif
   /** @}  */
 
   // 20.3.3 comparisons
   /** @defgroup comparison_functors Comparison Classes
    * @ingroup functors
    *
    *  The library provides six wrapper functors for all the basic comparisons
    *  in C++, like @c <.
    *
    *  @{
    */
   /// One of the @link comparison_functors comparison functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct equal_to : public binary_function<_Tp, _Tp, bool>
     {
       bool
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x == __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct equal_to<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) == std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) == std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) == std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link comparison_functors comparison functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct not_equal_to : public binary_function<_Tp, _Tp, bool>
     {
       bool
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x != __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct not_equal_to<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) != std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) != std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) != std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link comparison_functors comparison functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct greater : public binary_function<_Tp, _Tp, bool>
     {
       bool
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x > __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct greater<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) > std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) > std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) > std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link comparison_functors comparison functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct less : public binary_function<_Tp, _Tp, bool>
     {
       bool
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x < __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct less<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) < std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) < std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) < std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link comparison_functors comparison functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct greater_equal : public binary_function<_Tp, _Tp, bool>
     {
       bool
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x >= __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct greater_equal<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) >= std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) >= std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) >= std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link comparison_functors comparison functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct less_equal : public binary_function<_Tp, _Tp, bool>
     {
       bool
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x <= __y; }
     };
+
+#if __cplusplus >= 201103L
+  template<>
+    struct less_equal<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) <= std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) <= std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) <= std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /** @}  */
 
   // 20.3.4 logical operations
   /** @defgroup logical_functors Boolean Operations Classes
    * @ingroup functors
    *
    *  Here are wrapper functors for Boolean operations: @c &&, @c ||,
    *  and @c !.
    *
    *  @{
    */
   /// One of the @link logical_functors Boolean operations functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct logical_and : public binary_function<_Tp, _Tp, bool>
     {
       bool
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x && __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct logical_and<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) && std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) && std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) && std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link logical_functors Boolean operations functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct logical_or : public binary_function<_Tp, _Tp, bool>
     {
       bool
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x || __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct logical_or<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) || std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) || std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) || std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   /// One of the @link logical_functors Boolean operations functors@endlink.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct logical_not : public unary_function<_Tp, bool>
     {
       bool
       operator()(const _Tp& __x) const
       { return !__x; }
     };
+
+#if __cplusplus >= 201103L
+  template<>
+    struct logical_not<void>
+    {
+      template <class _Tp>
+      constexpr auto
+      operator()(_Tp&& __x) const
+      noexcept(noexcept(!std::forward<_Tp>(__x)))
+      -> decltype(!std::forward<_Tp>(__x))
+      {
+	return !std::forward<_Tp>(__x);
+      }
+      typedef void is_transparent;
+  };
+#endif
   /** @}  */
 
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // DR 660. Missing Bitwise Operations.
-  template<typename _Tp>
+  template<typename _Tp = void>
     struct bit_and : public binary_function<_Tp, _Tp, _Tp>
     {
       _Tp
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x & __y; }
     };
 
-  template<typename _Tp>
+#if __cplusplus >= 201103L
+  template<>
+    struct bit_and<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) & std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) & std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) & std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
+  template<typename _Tp = void>
     struct bit_or : public binary_function<_Tp, _Tp, _Tp>
     {
       _Tp
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x | __y; }
     };
 
-  template<typename _Tp>
+#if __cplusplus >= 201103L
+  template<>
+    struct bit_or<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) | std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) | std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) | std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
+  template<typename _Tp = void>
     struct bit_xor : public binary_function<_Tp, _Tp, _Tp>
     {
       _Tp
       operator()(const _Tp& __x, const _Tp& __y) const
       { return __x ^ __y; }
     };
 
+#if __cplusplus >= 201103L
+  template<>
+    struct bit_xor<void>
+    {
+      template <class _Tp, class _Up>
+      constexpr auto
+      operator()(_Tp&& __x, _Up&& __y) const
+      noexcept(noexcept(std::forward<_Tp>(__x) ^ std::forward<_Up>(__y)))
+      -> decltype(std::forward<_Tp>(__x) ^ std::forward<_Up>(__y))
+      {
+	return std::forward<_Tp>(__x) ^ std::forward<_Up>(__y);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
+  template<typename _Tp = void>
+    struct bit_not : public unary_function<_Tp, _Tp>
+    {
+      _Tp
+      operator()(const _Tp& __x) const
+      { return ~__x; }
+    };
+
+#if __cplusplus >= 201103L
+  template<>
+    struct bit_not<void>
+    {
+      template <class _Tp>
+      constexpr auto
+      operator()(_Tp&& __x) const
+      noexcept(noexcept(~std::forward<_Tp>(__x)))
+      -> decltype(~std::forward<_Tp>(__x))
+      {
+	return ~std::forward<_Tp>(__x);
+      }
+      typedef void is_transparent;
+  };
+#endif
+
   // 20.3.5 negators
   /** @defgroup negators Negators
    * @ingroup functors
    *
    *  The functions @c not1 and @c not2 each take a predicate functor
    *  and return an instance of @c unary_negate or
    *  @c binary_negate, respectively.  These classes are functors whose
    *  @c operator() performs the stored predicate function and then returns
    *  the negation of the result.
    *
Index: testsuite/20_util/headers/functional/generic_function_objects.cc
===================================================================
--- testsuite/20_util/headers/functional/generic_function_objects.cc	(revision 0)
+++ testsuite/20_util/headers/functional/generic_function_objects.cc	(working copy)
@@ -0,0 +1,37 @@ 
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+// Copyright (C) 2013 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 3, 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 COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <functional>
+#include <type_traits>
+
+struct A{};
+extern A a;
+struct B{};
+struct C{};
+C operator<(A&,B&&);
+struct D{};
+struct E{};
+E& operator~(D);
+static_assert (std::is_same<
+    decltype(std::less<void>{} (a, B{})),
+    C >::value, "Meh?");
+static_assert (std::is_same<
+    decltype(std::bit_not<void>{} (D{})),
+    E& >::value, "Bah...");