From 3b3352dead5c00ec49ff619607e5507c8a7314e2 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Sat, 26 Nov 2016 15:49:40 +0000 Subject: [PATCH] Implement the 'detection idiom' from LFTS v2 llvm-svn: 287981 --- libcxx/include/experimental/type_traits | 85 ++++++++++++++++++++++ .../meta/meta.detect/detected_or.pass.cpp | 40 ++++++++++ .../utilities/meta/meta.detect/detected_t.pass.cpp | 48 ++++++++++++ .../meta/meta.detect/is_detected.pass.cpp | 37 ++++++++++ .../meta.detect/is_detected_convertible.pass.cpp | 50 +++++++++++++ .../meta/meta.detect/is_detected_exact.pass.cpp | 49 +++++++++++++ 6 files changed, 309 insertions(+) create mode 100644 libcxx/test/std/experimental/utilities/meta/meta.detect/detected_or.pass.cpp create mode 100644 libcxx/test/std/experimental/utilities/meta/meta.detect/detected_t.pass.cpp create mode 100644 libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected.pass.cpp create mode 100644 libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected_convertible.pass.cpp create mode 100644 libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected_exact.pass.cpp diff --git a/libcxx/include/experimental/type_traits b/libcxx/include/experimental/type_traits index ae49fc17..524d980 100644 --- a/libcxx/include/experimental/type_traits +++ b/libcxx/include/experimental/type_traits @@ -172,6 +172,45 @@ inline namespace fundamentals_v1 { template using raw_invocation_type_t = typename raw_invocation_type::type; + // 3.3.3, Logical operator traits + template struct conjunction; + template constexpr bool conjunction_v = conjunction::value; + template struct disjunction; + template constexpr bool disjunction_v = disjunction::value; + template struct negation; + template constexpr bool negation_v = negation::value; + + // 3.3.4, Detection idiom + template using void_t = void; + + struct nonesuch { + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; + }; + + template class Op, class... Args> + using is_detected = see below; + template class Op, class... Args> + constexpr bool is_detected_v = is_detected::value; + template class Op, class... Args> + using detected_t = see below; + template class Op, class... Args> + using detected_or = see below; + template class Op, class... Args> + using detected_or_t = typename detected_or::type; + template class Op, class... Args> + using is_detected_exact = is_same>; + template class Op, class... Args> + constexpr bool is_detected_exact_v + = is_detected_exact::value; + template class Op, class... Args> + using is_detected_convertible = is_convertible, To>; + template class Op, class... Args> + constexpr bool is_detected_convertible_v + = is_detected_convertible::value; + } // namespace fundamentals_v1 } // namespace experimental } // namespace std @@ -420,6 +459,52 @@ template using raw_invocation_type_t = typename raw_invocation_type<_Tp>::type; */ +// 3.3.4, Detection idiom +template using void_t = void; + +struct nonesuch { + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch (nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; + }; + +template class _Op, class... _Args> +struct _DETECTOR { + using value_t = false_type; + using type = _Default; + }; + +template class _Op, class... _Args> +struct _DETECTOR<_Default, void_t<_Op<_Args...>>, _Op, _Args...> { + using value_t = true_type; + using type = _Op<_Args...>; + }; + + +template class _Op, class... _Args> + using is_detected = typename _DETECTOR::value_t; +template class _Op, class... _Args> + using detected_t = typename _DETECTOR::type; +template class _Op, class... _Args> + _LIBCPP_CONSTEXPR bool is_detected_v = is_detected<_Op, _Args...>::value; + +template class _Op, class... _Args> + using detected_or = _DETECTOR; +template class _Op, class... _Args> + using detected_or_t = typename detected_or::type; + +template class _Op, class... _Args> + using is_detected_exact = is_same>; +template class _Op, class... _Args> + _LIBCPP_CONSTEXPR bool is_detected_exact_v = is_detected_exact::value; + +template class _Op, class... _Args> + using is_detected_convertible = is_convertible, To>; +template class _Op, class... _Args> + _LIBCPP_CONSTEXPR bool is_detected_convertible_v = is_detected_convertible::value; + + _LIBCPP_END_NAMESPACE_LFTS #endif /* _LIBCPP_STD_VER > 11 */ diff --git a/libcxx/test/std/experimental/utilities/meta/meta.detect/detected_or.pass.cpp b/libcxx/test/std/experimental/utilities/meta/meta.detect/detected_or.pass.cpp new file mode 100644 index 0000000..ffce814 --- /dev/null +++ b/libcxx/test/std/experimental/utilities/meta/meta.detect/detected_or.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11 +// + +#include +#include + +#include "test_macros.h" + +namespace ex = std::experimental; + +template + using hasFoo = typename T::Foo; + +struct yesFoo { + using Foo = int; +}; + +struct noFoo { +}; + + +template +void test() { + static_assert( std::is_same::type>::value, "" ); + static_assert( std::is_same >::value, "" ); +} + +int main () { + test(); + test(); +} diff --git a/libcxx/test/std/experimental/utilities/meta/meta.detect/detected_t.pass.cpp b/libcxx/test/std/experimental/utilities/meta/meta.detect/detected_t.pass.cpp new file mode 100644 index 0000000..136fb06 --- /dev/null +++ b/libcxx/test/std/experimental/utilities/meta/meta.detect/detected_t.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11 +// + +#include +#include + +#include "test_macros.h" + +namespace ex = std::experimental; + +template + using callFoo = decltype(std::declval().Foo()); + +struct yesFoo { + int Foo() { return 0; } +}; + +struct noFoo { +}; + +struct wrongFoo { + std::string Foo() { return ""; } +}; + +struct convertibleFoo { + long Foo() { return 0; } +}; + + +template +void test() { + static_assert( std::is_same>::value, "" ); +} + +int main () { + test(); + test(); // lookup failure returns nonesuch + test(); +} diff --git a/libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected.pass.cpp b/libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected.pass.cpp new file mode 100644 index 0000000..d8528a2 --- /dev/null +++ b/libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11 +// + +#include +#include + +#include "test_macros.h" + +namespace ex = std::experimental; + +template + using copy_assign_t = decltype(std::declval() = std::declval()); + +struct not_assignable { + not_assignable & operator=(const not_assignable&) = delete; +}; + +template +void test() { + static_assert( b == ex::is_detected ::value, "" ); + static_assert( b == ex::is_detected_v, "" ); +} + +int main () { + test(); + test(); + test(); +} diff --git a/libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected_convertible.pass.cpp b/libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected_convertible.pass.cpp new file mode 100644 index 0000000..8d1e0ae --- /dev/null +++ b/libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected_convertible.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11 +// + +#include +#include + +#include "test_macros.h" + +namespace ex = std::experimental; + +template + using callFoo = decltype(std::declval().Foo()); + +struct yesFoo { + int Foo() { return 0; } +}; + +struct noFoo { +}; + +struct wrongFoo { + std::string Foo() { return ""; } +}; + +struct convertibleFoo { + long Foo() { return 0; } +}; + + +template +void test() { + static_assert( b == ex::is_detected_convertible ::value, "" ); + static_assert( b == ex::is_detected_convertible_v, "" ); +} + +int main () { + test(); + test(); + test(); + test(); +} diff --git a/libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected_exact.pass.cpp b/libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected_exact.pass.cpp new file mode 100644 index 0000000..e9e5d8c --- /dev/null +++ b/libcxx/test/std/experimental/utilities/meta/meta.detect/is_detected_exact.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11 +// + +#include +#include + +#include "test_macros.h" + +namespace ex = std::experimental; + +template + using callFoo = decltype(std::declval().Foo()); + +struct yesFoo { + int Foo() { return 0; } +}; + +struct noFoo { +}; + +struct wrongFoo { + std::string Foo() { return ""; } +}; + +struct convertibleFoo { + long Foo() { return 0; } +}; + +template +void test() { + static_assert( b == ex::is_detected_exact ::value, "" ); + static_assert( b == ex::is_detected_exact_v, "" ); +} + +int main () { + test(); + test(); + test(); + test(); +} -- 2.7.4