mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-10 10:14:49 +08:00
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
This commit is contained in:
parent
9735e6ea8e
commit
6af6bef4ac
@ -1,3 +1,14 @@
|
|||||||
|
2015-07-01 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
|
* 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 <jwakely@redhat.com>
|
2015-06-30 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
* doc/Makefile.am (stamp-pdf-doxygen): Grep for LaTeX errors in log.
|
* doc/Makefile.am (stamp-pdf-doxygen): Grep for LaTeX errors in log.
|
||||||
|
@ -328,14 +328,13 @@ not in any particular release.
|
|||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<?dbhtml bgcolor="#C8B0B0" ?>
|
|
||||||
<entry>
|
<entry>
|
||||||
<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf">
|
<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf">
|
||||||
N4502
|
N4502
|
||||||
</link>
|
</link>
|
||||||
</entry>
|
</entry>
|
||||||
<entry> Support for the C++ Detection Idiom, V2 </entry>
|
<entry> Support for the C++ Detection Idiom, V2 </entry>
|
||||||
<entry>N</entry>
|
<entry>Y</entry>
|
||||||
<entry>Library Fundamentals 2 TS</entry>
|
<entry>Library Fundamentals 2 TS</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
@ -220,6 +220,59 @@ template <typename _From, typename _To>
|
|||||||
// raw_invocation_type_t (still unimplemented)
|
// raw_invocation_type_t (still unimplemented)
|
||||||
_GLIBCXX_END_NAMESPACE_VERSION
|
_GLIBCXX_END_NAMESPACE_VERSION
|
||||||
} // namespace fundamentals_v1
|
} // namespace fundamentals_v1
|
||||||
|
|
||||||
|
inline namespace fundamentals_v2
|
||||||
|
{
|
||||||
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
|
|
||||||
|
#define __cpp_lib_experimental_detect 201505
|
||||||
|
|
||||||
|
// [meta.detect]
|
||||||
|
|
||||||
|
template<typename...> using void_t = void;
|
||||||
|
|
||||||
|
struct nonesuch
|
||||||
|
{
|
||||||
|
nonesuch() = delete;
|
||||||
|
~nonesuch() = delete;
|
||||||
|
nonesuch(nonesuch const&) = delete;
|
||||||
|
void operator=(nonesuch const&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<template<typename...> class _Op, typename... _Args>
|
||||||
|
using is_detected
|
||||||
|
= typename std::__detector<nonesuch, void, _Op, _Args...>::value_t;
|
||||||
|
|
||||||
|
template<template<typename...> class _Op, typename... _Args>
|
||||||
|
constexpr bool is_detected_v = is_detected<_Op, _Args...>::value;
|
||||||
|
|
||||||
|
template<template<typename...> class _Op, typename... _Args>
|
||||||
|
using detected_t
|
||||||
|
= typename std::__detector<nonesuch, void, _Op, _Args...>::type;
|
||||||
|
|
||||||
|
template<typename _Default, template<typename...> class _Op, typename... _Args>
|
||||||
|
using detected_or = std::__detected_or<_Default, _Op, _Args...>;
|
||||||
|
|
||||||
|
template<typename _Default, template<typename...> class _Op, typename... _Args>
|
||||||
|
using detected_or_t = typename detected_or<_Default, _Op, _Args...>::type;
|
||||||
|
|
||||||
|
template<typename Expected, template<typename...> class _Op, typename... _Args>
|
||||||
|
using is_detected_exact = is_same<Expected, detected_t<_Op, _Args...>>;
|
||||||
|
|
||||||
|
template<typename Expected, template<typename...> class _Op, typename... _Args>
|
||||||
|
constexpr bool is_detected_exact_v
|
||||||
|
= is_detected_exact<Expected, _Op, _Args...>::value;
|
||||||
|
|
||||||
|
template<typename _To, template<typename...> class _Op, typename... _Args>
|
||||||
|
using is_detected_convertible
|
||||||
|
= is_convertible<detected_t<_Op, _Args...>, _To>;
|
||||||
|
|
||||||
|
template<typename _To, template<typename...> 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 experimental
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
|
@ -2417,6 +2417,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||||||
template<typename...> using void_t = void;
|
template<typename...> using void_t = void;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Implementation of the detection idiom (negative case).
|
||||||
|
template<typename _Default, typename _AlwaysVoid,
|
||||||
|
template<typename...> class _Op, typename... _Args>
|
||||||
|
struct __detector
|
||||||
|
{
|
||||||
|
using value_t = false_type;
|
||||||
|
using type = _Default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Implementation of the detection idiom (positive case).
|
||||||
|
template<typename _Default, template<typename...> 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<typename _Default, template<typename...> class _Op,
|
||||||
|
typename... _Args>
|
||||||
|
using __detected_or = __detector<_Default, void, _Op, _Args...>;
|
||||||
|
|
||||||
|
// _Op<_Args...> if that is a valid type, otherwise _Default.
|
||||||
|
template<typename _Default, template<typename...> 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<template<typename...> class _Default,
|
||||||
|
template<typename...> class _Op, typename... _Args>
|
||||||
|
using __detected_or_t_ =
|
||||||
|
__detected_or_t<_Default<_Args...>, _Op, _Args...>;
|
||||||
|
|
||||||
/// @} group metaprogramming
|
/// @} group metaprogramming
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
85
libstdc++-v3/testsuite/experimental/type_traits/detection.cc
Normal file
85
libstdc++-v3/testsuite/experimental/type_traits/detection.cc
Normal file
@ -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
|
||||||
|
// <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// { dg-options "-std=gnu++14" }
|
||||||
|
// { dg-do compile }
|
||||||
|
|
||||||
|
#include <experimental/type_traits>
|
||||||
|
|
||||||
|
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 <class T>
|
||||||
|
using copy_assign_t = decltype(declval<T&>() = declval<T const &>());
|
||||||
|
|
||||||
|
// plausible implementation for the is_assignable type trait:
|
||||||
|
template <class T>
|
||||||
|
using is_copy_assignable = is_detected<copy_assign_t, T>;
|
||||||
|
|
||||||
|
// plausible implementation for an augmented is_assignable type trait
|
||||||
|
// that also checks the return type:
|
||||||
|
template <class T>
|
||||||
|
using is_canonical_copy_assignable = is_detected_exact<T&, copy_assign_t, T>;
|
||||||
|
|
||||||
|
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<A>::value, "A is copy assignable" );
|
||||||
|
static_assert( is_copy_assignable<B>::value, "B is copy assignable" );
|
||||||
|
static_assert( is_copy_assignable<C>::value, "C is copy assignable" );
|
||||||
|
static_assert( !is_copy_assignable<D>::value, "D is not copy assignable" );
|
||||||
|
static_assert( !is_copy_assignable<E>::value, "E is not copy assignable" );
|
||||||
|
|
||||||
|
static_assert( is_canonical_copy_assignable<A>::value,
|
||||||
|
"A has canonical copy assignment" );
|
||||||
|
static_assert( is_canonical_copy_assignable<B>::value,
|
||||||
|
"B has canonical copy assignment" );
|
||||||
|
static_assert( !is_canonical_copy_assignable<C>::value,
|
||||||
|
"C does not have canonical copy assignment" );
|
||||||
|
static_assert( !is_canonical_copy_assignable<D>::value,
|
||||||
|
"D does not have canonical copy assignment" );
|
||||||
|
static_assert( !is_canonical_copy_assignable<E>::value,
|
||||||
|
"E does not have canonical copy assignment" );
|
||||||
|
|
||||||
|
// archetypal helper alias for a particular type member:
|
||||||
|
template <class T>
|
||||||
|
using diff_t = typename T::difference_type;
|
||||||
|
// alias the type member, if it exists, otherwise alias ptrdiff_t:
|
||||||
|
template <class Ptr>
|
||||||
|
using difference_type = detected_or_t<ptrdiff_t, diff_t, Ptr>;
|
||||||
|
|
||||||
|
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<difference_type<has>, char>, "has" );
|
||||||
|
static_assert( is_same_v<difference_type<has_not>, ptrdiff_t>, "has not" );
|
||||||
|
static_assert( is_same_v<difference_type<inherits>, char>, "inherits" );
|
||||||
|
static_assert( is_same_v<difference_type<hides>, ptrdiff_t>, "hides" );
|
||||||
|
static_assert( is_same_v<difference_type<reveals>, char>, "reveals" );
|
Loading…
Reference in New Issue
Block a user