From 6af6bef4ac3175302efe92de9bdd423fbe4b40d8 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 1 Jul 2015 13:23:54 +0100 Subject: [PATCH] Implement N4502, the C++ Detection Idiom. * doc/xml/manual/status_cxx2017.xml: Update status table. * include/experimental/type_traits (void_t, is_detected, is_detected_v, detected_t, detected_or, detected_or_t, is_detected_exact, is_detected_exact_v, is_detected_convertible, is_detected_convertible_v): Define. * include/std/type_traits (__detector, __detected_or, __detected_or_t, __detected_or_t_): Define. * testsuite/experimental/type_traits/detection.cc: New. From-SVN: r225242 --- libstdc++-v3/ChangeLog | 11 +++ libstdc++-v3/doc/xml/manual/status_cxx2017.xml | 3 +- libstdc++-v3/include/experimental/type_traits | 53 ++++++++++++++ libstdc++-v3/include/std/type_traits | 35 +++++++++ .../experimental/type_traits/detection.cc | 85 ++++++++++++++++++++++ 5 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 libstdc++-v3/testsuite/experimental/type_traits/detection.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index f159f78..e349937 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,14 @@ +2015-07-01 Jonathan Wakely + + * doc/xml/manual/status_cxx2017.xml: Update status table. + * include/experimental/type_traits (void_t, is_detected, + is_detected_v, detected_t, detected_or, detected_or_t, + is_detected_exact, is_detected_exact_v, is_detected_convertible, + is_detected_convertible_v): Define. + * include/std/type_traits (__detector, __detected_or, __detected_or_t, + __detected_or_t_): Define. + * testsuite/experimental/type_traits/detection.cc: New. + 2015-06-30 Jonathan Wakely * doc/Makefile.am (stamp-pdf-doxygen): Grep for LaTeX errors in log. diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml index d110572..07e2dbe 100644 --- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml +++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml @@ -328,14 +328,13 @@ not in any particular release. - N4502 Support for the C++ Detection Idiom, V2 - N + Y Library Fundamentals 2 TS diff --git a/libstdc++-v3/include/experimental/type_traits b/libstdc++-v3/include/experimental/type_traits index db78eec..b0ed3b0 100644 --- a/libstdc++-v3/include/experimental/type_traits +++ b/libstdc++-v3/include/experimental/type_traits @@ -220,6 +220,59 @@ template // raw_invocation_type_t (still unimplemented) _GLIBCXX_END_NAMESPACE_VERSION } // namespace fundamentals_v1 + +inline namespace fundamentals_v2 +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#define __cpp_lib_experimental_detect 201505 + +// [meta.detect] + +template using void_t = void; + +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template class _Op, typename... _Args> + using is_detected + = typename std::__detector::value_t; + +template class _Op, typename... _Args> + constexpr bool is_detected_v = is_detected<_Op, _Args...>::value; + +template class _Op, typename... _Args> + using detected_t + = typename std::__detector::type; + +template class _Op, typename... _Args> + using detected_or = std::__detected_or<_Default, _Op, _Args...>; + +template class _Op, typename... _Args> + using detected_or_t = typename detected_or<_Default, _Op, _Args...>::type; + +template class _Op, typename... _Args> + using is_detected_exact = is_same>; + +template class _Op, typename... _Args> + constexpr bool is_detected_exact_v + = is_detected_exact::value; + +template class _Op, typename... _Args> + using is_detected_convertible + = is_convertible, _To>; + +template class _Op, typename... _Args> + constexpr bool is_detected_convertible_v + = is_detected_convertible<_To, _Op, _Args...>::value; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace fundamentals_v2 } // namespace experimental } // namespace std diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index e09c856..55ca916 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -2417,6 +2417,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template using void_t = void; #endif + /// Implementation of the detection idiom (negative case). + template class _Op, typename... _Args> + struct __detector + { + using value_t = false_type; + using type = _Default; + }; + + /// Implementation of the detection idiom (positive case). + template class _Op, + typename... _Args> + struct __detector<_Default, __void_t<_Op<_Args...>>, _Op, _Args...> + { + using value_t = true_type; + using type = _Op<_Args...>; + }; + + // Detect whether _Op<_Args...> is a valid type, use _Default if not. + template class _Op, + typename... _Args> + using __detected_or = __detector<_Default, void, _Op, _Args...>; + + // _Op<_Args...> if that is a valid type, otherwise _Default. + template class _Op, + typename... _Args> + using __detected_or_t + = typename __detected_or<_Default, _Op, _Args...>::type; + + // _Op<_Args...> if that is a valid type, otherwise _Default<_Args...>. + template class _Default, + template class _Op, typename... _Args> + using __detected_or_t_ = + __detected_or_t<_Default<_Args...>, _Op, _Args...>; + /// @} group metaprogramming /** diff --git a/libstdc++-v3/testsuite/experimental/type_traits/detection.cc b/libstdc++-v3/testsuite/experimental/type_traits/detection.cc new file mode 100644 index 0000000..45d0692 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/type_traits/detection.cc @@ -0,0 +1,85 @@ +// Copyright (C) 2015 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 +// . + +// { dg-options "-std=gnu++14" } +// { dg-do compile } + +#include + +using std::declval; +using std::ptrdiff_t; +using std::experimental::is_detected; +using std::experimental::is_detected_exact; +using std::experimental::detected_or_t; +using std::experimental::is_same_v; + +// Examples taken from N4502 + +// archetypal helper alias for a copy assignment operation: +template +using copy_assign_t = decltype(declval() = declval()); + +// plausible implementation for the is_assignable type trait: +template + using is_copy_assignable = is_detected; + +// plausible implementation for an augmented is_assignable type trait +// that also checks the return type: +template + using is_canonical_copy_assignable = is_detected_exact; + +struct A { }; +struct B { B& operator=(const B&); }; +struct C { void operator=(const C&); }; +struct D { D& operator=(D&); }; +struct E { E& operator=(E&&); }; + +static_assert( is_copy_assignable::value, "A is copy assignable" ); +static_assert( is_copy_assignable::value, "B is copy assignable" ); +static_assert( is_copy_assignable::value, "C is copy assignable" ); +static_assert( !is_copy_assignable::value, "D is not copy assignable" ); +static_assert( !is_copy_assignable::value, "E is not copy assignable" ); + +static_assert( is_canonical_copy_assignable::value, + "A has canonical copy assignment" ); +static_assert( is_canonical_copy_assignable::value, + "B has canonical copy assignment" ); +static_assert( !is_canonical_copy_assignable::value, + "C does not have canonical copy assignment" ); +static_assert( !is_canonical_copy_assignable::value, + "D does not have canonical copy assignment" ); +static_assert( !is_canonical_copy_assignable::value, + "E does not have canonical copy assignment" ); + +// archetypal helper alias for a particular type member: +template + using diff_t = typename T::difference_type; +// alias the type member, if it exists, otherwise alias ptrdiff_t: +template + using difference_type = detected_or_t; + +struct has { using difference_type = char; }; +struct has_not { }; +struct inherits : has { }; +struct hides : private has { }; +struct reveals : private has { using has::difference_type; }; + +static_assert( is_same_v, char>, "has" ); +static_assert( is_same_v, ptrdiff_t>, "has not" ); +static_assert( is_same_v, char>, "inherits" ); +static_assert( is_same_v, ptrdiff_t>, "hides" ); +static_assert( is_same_v, char>, "reveals" ); -- 2.7.4