Implement detection idiom toolkit

This commit is contained in:
Glen Fernandes
2017-12-04 08:33:21 -05:00
parent 5d5c651ea6
commit 35c105501b
21 changed files with 662 additions and 2 deletions

View File

@ -170,6 +170,17 @@ matrix:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
- os: linux
compiler: clang++-5.0
env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=03,11,14,1z
addons:
apt:
packages:
- clang-5.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-5.0
- os: osx
env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11,14,1z
osx_image: xcode8.3

View File

@ -18,8 +18,8 @@ current maintainer of the library.
This version of type traits library is based on contributions by
Adobe Systems Inc, David Abrahams, Steve Cleary,
Beman Dawes, Aleksey Gurtovoy, Howard Hinnant, Jesse Jones, Mat Marcus,
Itay Maman, John Maddock, Thorsten Ottosen, Robert Ramey, Jeremy Siek
and Antony Polukhin.
Itay Maman, John Maddock, Thorsten Ottosen, Robert Ramey, Jeremy Siek,
Antony Polukhin and Glen Fernandes.
Mat Marcus and Jesse Jones invented, and
[@http://opensource.adobe.com/project4/project.shtml published a paper describing],

24
doc/detected.qbk Normal file
View File

@ -0,0 +1,24 @@
[/
Copyright 2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt).
]
[section:detected detected]
template<template<class...> class Op, class... Args>
using detected_t = __below;
__alias `Op<Args...>` if it is a valid template-id, otherwise
`boost::nonesuch`.
__std_paper [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf N4502]
__compat Requires C++11 variadic templates and C++11 template aliases.
__header `#include <boost/type_traits/detected.hpp>`
[endsect]

38
doc/detected_or.qbk Normal file
View File

@ -0,0 +1,38 @@
[/
Copyright 2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt).
]
[section:detected_or detected_or]
template<class Default, template<class...> class Op, class... Args>
using detected_or = __below;
template<class Default, template<class...> class Op, class... Args>
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
__alias An unspecified type with two public member type definitions:
* `value_t` is __true_type if `Op<Args...>` is a valid template-id, otherwise
__false_type
* `type` is `Op<Args...>` if it is a valid template-id, otherwise `Default`
__std_paper [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf N4502]
__compat Requires C++11 variadic templates and C++11 template aliases.
__header `#include <boost/type_traits/detected_or.hpp>`
__examples
template<class T>
using difference_t = typename T::difference_type;
template<class T>
using difference_type = boost::detected_or_t<std::ptrdiff_t, difference_t, T>;
[endsect]

42
doc/is_detected.qbk Normal file
View File

@ -0,0 +1,42 @@
[/
Copyright 2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt).
]
[section:is_detected is_detected]
template<template<class...> class Op, class... Args>
using is_detected = __below;
template<template<class...> class Op, class... Args>
constexpr bool is_detected_v = is_detected<Op, Args...>::value;
__alias If `Op<Args...>` is a valid template-id, aliases __true_type,
otherwise aliases __false_type.
__std_paper [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf N4502]
__compat Requires C++11 variadic templates and C++11 template aliases.
__header `#include <boost/type_traits/is_detected.hpp>`
__examples
template<class T>
using clear_t = decltype(boost::declval<T&>().clear());
template<class T>
void clear(T& value)
{
if constexpr (boost::is_detected_v<clear_t, T>) {
value.clear();
} else {
value = T();
}
}
[endsect]

View File

@ -0,0 +1,31 @@
[/
Copyright 2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt).
]
[section:is_detected_convertible is_detected_convertible]
template<class To, template<class...> class Op, class... Args>
using is_detected_convertible = is_convertible<detected_t<Op, Args...>, To>;
template<class To, template<class...> class Op, class... Args>
constexpr bool is_detected_convertible_v = is_detected_convertible<Op, Args...>::value;
__std_paper [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf N4502]
__compat Requires C++11 variadic templates and C++11 template aliases.
__header `#include <boost/type_traits/is_detected_convertible.hpp>`
__examples
template<class T>
using size_type_t = typename T::size_type;
static_assert(boost::is_detected_convertible_v<std::size_t, size_type_t, T>);
[endsect]

31
doc/is_detected_exact.qbk Normal file
View File

@ -0,0 +1,31 @@
[/
Copyright 2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt).
]
[section:is_detected_exact is_detected_exact]
template<class Expected, template<class...> class Op, class... Args>
using is_detected_exact = is_same<Expected, detected_t<Op, Args...> >;
template<class Expected, template<class...> class Op, class... Args>
constexpr bool is_detected_exact_v = is_detected_exact<Op, Args...>::value;
__std_paper [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf N4502]
__compat Requires C++11 variadic templates and C++11 template aliases.
__header `#include <boost/type_traits/is_detected_exact.hpp>`
__examples
template<class T>
using difference_t = typename T::difference_type;
static_assert(boost::is_detected_exact_v<std::ptrdiff_t, difference_t, T>);
[endsect]

21
doc/nonesuch.qbk Normal file
View File

@ -0,0 +1,21 @@
[/
Copyright 2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt).
]
[section:nonesuch nonesuch]
struct nonesuch {
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(const nonesuch&) = delete;
void operator=(const nonesuch&) = delete;
};
__header `#include <boost/type_traits/nonesuch.hpp>`
[endsect]

View File

@ -31,7 +31,9 @@
[def __true_type [link boost_typetraits.reference.integral_constant true_type]]
[def __false_type [link boost_typetraits.reference.integral_constant false_type]]
[def __integral_constant [link boost_typetraits.reference.integral_constant integral_constant]]
[def __alias [*Aliases:]]
[def __inherit [*Inherits:]]
[def __std_paper [*C++ Standard Paper:]]
[def __std_ref [*C++ Standard Reference:]]
[def __header [*Header:]]
[def __compat [*Compiler Compatibility:]]
@ -145,6 +147,13 @@
[def __type_identity [link boost_typetraits.reference.type_identity type_identity]]
[def __declval [link boost_typetraits.reference.declval declval]]
[def __detected [link boost_typetraits.reference.detected detected]]
[def __detected_or [link boost_typetraits.reference.detected_or detected_or]]
[def __is_detected [link boost_typetraits.reference.is_detected is_detected]]
[def __is_detected_convertible [link boost_typetraits.reference.is_detected_convertible is_detected_convertible]]
[def __is_detected_exact [link boost_typetraits.reference.is_detected_exact is_detected_exact]]
[def __nonesuch [link boost_typetraits.reference.nonesuch nonesuch]]
[def __compat [*Compiler Compatibility:]]
[template all_compilers[] __compat All current compilers are supported by this trait.]
[template has_binary_operator_compat[] __compat Requires working SFINAE (i.e. BOOST_NO_SFINAE is not set). Only a minority of rather old compilers do not support this.]
@ -204,6 +213,8 @@ that is the result of the transformation.
[include copy_cv.qbk]
[include decay.qbk]
[include declval.qbk]
[include detected.qbk]
[include detected_or.qbk]
[include extent.qbk]
[include floating_point_promotion.qbk]
[include function_traits.qbk]
@ -289,6 +300,9 @@ See __has_trivial_constructor.
[include is_copy_constructible.qbk]
[include is_default_constructible.qbk]
[include is_destructible.qbk]
[include is_detected.qbk]
[include is_detected_convertible.qbk]
[include is_detected_exact.qbk]
[include is_empty.qbk]
[include is_enum.qbk]
[include is_final.qbk]
@ -323,6 +337,7 @@ See __has_trivial_constructor.
[include make_signed.qbk]
[include make_unsigned.qbk]
[include make_void.qbk]
[include nonesuch.qbk]
[include promote.qbk]
[include rank.qbk]

View File

@ -0,0 +1,35 @@
/*
Copyright 2017-2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_TT_DETAIL_DETECTOR_HPP_INCLUDED
#define BOOST_TT_DETAIL_DETECTOR_HPP_INCLUDED
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/make_void.hpp>
namespace boost {
namespace detail {
template<class Default, class, template<class...> class, class...>
struct detector {
using value_t = boost::false_type;
using type = Default;
};
template<class Default, template<class...> class Op, class... Args>
struct detector<Default, typename boost::make_void<Op<Args...> >::type, Op,
Args...> {
using value_t = boost::true_type;
using type = Op<Args...>;
};
} /* detail */
} /* boost */
#endif

View File

@ -0,0 +1,24 @@
/*
Copyright 2017-2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_TT_DETECTED_HPP_INCLUDED
#define BOOST_TT_DETECTED_HPP_INCLUDED
#include <boost/type_traits/detail/detector.hpp>
#include <boost/type_traits/nonesuch.hpp>
namespace boost {
template<template<class...> class Op, class... Args>
using detected_t = typename
detail::detector<nonesuch, void, Op, Args...>::type;
} /* boost */
#endif

View File

@ -0,0 +1,25 @@
/*
Copyright 2017-2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_TT_DETECTED_OR_HPP_INCLUDED
#define BOOST_TT_DETECTED_OR_HPP_INCLUDED
#include <boost/type_traits/detail/detector.hpp>
namespace boost {
template<class Default, template<class...> class Op, class... Args>
using detected_or = detail::detector<Default, void, Op, Args...>;
template<class Default, template<class...> class Op, class... Args>
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
} /* boost */
#endif

View File

@ -0,0 +1,29 @@
/*
Copyright 2017-2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_TT_IS_DETECTED_HPP_INCLUDED
#define BOOST_TT_IS_DETECTED_HPP_INCLUDED
#include <boost/type_traits/detail/detector.hpp>
#include <boost/type_traits/nonesuch.hpp>
namespace boost {
template<template<class...> class Op, class... Args>
using is_detected = typename
detail::detector<nonesuch, void, Op, Args...>::value_t;
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
template<template<class...> class Op, class... Args>
constexpr bool is_detected_v = is_detected<Op, Args...>::value;
#endif
} /* boost */
#endif

View File

@ -0,0 +1,29 @@
/*
Copyright 2017-2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_TT_IS_DETECTED_CONVERTIBLE_HPP_INCLUDED
#define BOOST_TT_IS_DETECTED_CONVERTIBLE_HPP_INCLUDED
#include <boost/type_traits/detected.hpp>
#include <boost/type_traits/is_convertible.hpp>
namespace boost {
template<class To, template<class...> class Op, class... Args>
using is_detected_convertible = is_convertible<detected_t<Op, Args...>, To>;
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
template<class To, template<class...> class Op, class... Args>
constexpr bool is_detected_convertible_v = is_detected_convertible<To, Op,
Args...>::value;
#endif
} /* boost */
#endif

View File

@ -0,0 +1,29 @@
/*
Copyright 2017-2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_TT_IS_DETECTED_EXACT_HPP_INCLUDED
#define BOOST_TT_IS_DETECTED_EXACT_HPP_INCLUDED
#include <boost/type_traits/detected.hpp>
#include <boost/type_traits/is_same.hpp>
namespace boost {
template<class Expected, template<class...> class Op, class... Args>
using is_detected_exact = is_same<Expected, detected_t<Op, Args...> >;
#if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
template<class Expected, template<class...> class Op, class... Args>
constexpr bool is_detected_exact_v = is_detected_exact<Expected, Op,
Args...>::value;
#endif
} /* boost */
#endif

View File

@ -0,0 +1,35 @@
/*
Copyright 2017 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_TT_NONESUCH_HPP_INCLUDED
#define BOOST_TT_NONESUCH_HPP_INCLUDED
#include <boost/config.hpp>
namespace boost {
#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS)
struct nonesuch {
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(const nonesuch&) = delete;
void operator=(const nonesuch&) = delete;
};
#else
class nonesuch {
nonesuch();
~nonesuch();
nonesuch(const nonesuch&);
void operator=(const nonesuch&);
};
#endif
} /* boost */
#endif

50
test/detected_or_test.cpp Normal file
View File

@ -0,0 +1,50 @@
/*
Copyright 2017 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/config.hpp>
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
!defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
#ifdef TEST_STD
#include <type_traits>
#else
#include <boost/type_traits/detected_or.hpp>
#endif
#include "check_integral_constant.hpp"
#include "check_type.hpp"
#define CHECK_FALSE(e) BOOST_CHECK_INTEGRAL_CONSTANT(e, false)
#define CHECK_TRUE(e) BOOST_CHECK_INTEGRAL_CONSTANT(e, true)
template<class T>
using type_t = typename T::type;
struct has_type {
using type = char;
};
struct no_type { };
TT_TEST_BEGIN(detected_or)
CHECK_FALSE((::tt::detected_or<bool, type_t, int>::value_t::value));
CHECK_TRUE((::tt::detected_or<bool, type_t, has_type>::value_t::value));
CHECK_FALSE((::tt::detected_or<bool, type_t, no_type>::value_t::value));
BOOST_CHECK_TYPE4(::tt::detected_or<bool, type_t, int>::type, bool);
BOOST_CHECK_TYPE4(::tt::detected_or<bool, type_t, has_type>::type, char);
BOOST_CHECK_TYPE4(::tt::detected_or<bool, type_t, no_type>::type, bool);
BOOST_CHECK_TYPE4(::tt::detected_or_t<bool, type_t, int>, bool);
BOOST_CHECK_TYPE4(::tt::detected_or_t<bool, type_t, has_type>, char);
BOOST_CHECK_TYPE4(::tt::detected_or_t<bool, type_t, no_type>, bool);
TT_TEST_END
#else
int main()
{
return 0;
}
#endif

44
test/detected_test.cpp Normal file
View File

@ -0,0 +1,44 @@
/*
Copyright 2017 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/config.hpp>
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
!defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
#ifdef TEST_STD
#include <type_traits>
#else
#include <boost/type_traits/detected.hpp>
#endif
#include "check_integral_constant.hpp"
#include "check_type.hpp"
#define CHECK_FALSE(e) BOOST_CHECK_INTEGRAL_CONSTANT(e, false)
#define CHECK_TRUE(e) BOOST_CHECK_INTEGRAL_CONSTANT(e, true)
template<class T>
using type_t = typename T::type;
struct has_type {
using type = char;
};
struct no_type { };
TT_TEST_BEGIN(detected)
BOOST_CHECK_TYPE3(::tt::detected_t<type_t, int>, boost::nonesuch);
BOOST_CHECK_TYPE3(::tt::detected_t<type_t, has_type>, char);
BOOST_CHECK_TYPE3(::tt::detected_t<type_t, no_type>, boost::nonesuch);
TT_TEST_END
#else
int main()
{
return 0;
}
#endif

View File

@ -0,0 +1,49 @@
/*
Copyright 2017-2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/config.hpp>
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
!defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
#ifdef TEST_STD
#include <type_traits>
#else
#include <boost/type_traits/is_detected_convertible.hpp>
#endif
#include "check_integral_constant.hpp"
#include "check_type.hpp"
#define CHECK_FALSE(e) BOOST_CHECK_INTEGRAL_CONSTANT(e, false)
#define CHECK_TRUE(e) BOOST_CHECK_INTEGRAL_CONSTANT(e, true)
template<class T>
using type_t = typename T::type;
struct has_type {
using type = char;
};
struct no_type { };
TT_TEST_BEGIN(is_detected_convertible)
CHECK_FALSE((::tt::is_detected_convertible<long, type_t, int>::value));
CHECK_TRUE((::tt::is_detected_convertible<long, type_t, has_type>::value));
CHECK_FALSE((::tt::is_detected_convertible<long, type_t, no_type>::value));
#ifndef BOOST_NO_CXX14_VARIABLE_TEMPLATES
CHECK_FALSE((::tt::is_detected_convertible_v<long, type_t, int>));
CHECK_TRUE((::tt::is_detected_convertible_v<long, type_t, has_type>));
CHECK_FALSE((::tt::is_detected_convertible_v<long, type_t, no_type>));
#endif
TT_TEST_END
#else
int main()
{
return 0;
}
#endif

View File

@ -0,0 +1,49 @@
/*
Copyright 2017-2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/config.hpp>
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
!defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
#ifdef TEST_STD
#include <type_traits>
#else
#include <boost/type_traits/is_detected_exact.hpp>
#endif
#include "check_integral_constant.hpp"
#include "check_type.hpp"
#define CHECK_FALSE(e) BOOST_CHECK_INTEGRAL_CONSTANT(e, false)
#define CHECK_TRUE(e) BOOST_CHECK_INTEGRAL_CONSTANT(e, true)
template<class T>
using type_t = typename T::type;
struct has_type {
using type = char;
};
struct no_type { };
TT_TEST_BEGIN(is_detected_exact)
CHECK_FALSE((::tt::is_detected_exact<char, type_t, int>::value));
CHECK_TRUE((::tt::is_detected_exact<char, type_t, has_type>::value));
CHECK_FALSE((::tt::is_detected_exact<char, type_t, no_type>::value));
#ifndef BOOST_NO_CXX14_VARIABLE_TEMPLATES
CHECK_FALSE((::tt::is_detected_exact_v<char, type_t, int>));
CHECK_TRUE((::tt::is_detected_exact_v<char, type_t, has_type>));
CHECK_FALSE((::tt::is_detected_exact_v<char, type_t, no_type>));
#endif
TT_TEST_END
#else
int main()
{
return 0;
}
#endif

49
test/is_detected_test.cpp Normal file
View File

@ -0,0 +1,49 @@
/*
Copyright 2017-2018 Glen Joseph Fernandes
<glenjofe -at- gmail.com>
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/config.hpp>
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
!defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
#ifdef TEST_STD
#include <type_traits>
#else
#include <boost/type_traits/is_detected.hpp>
#endif
#include "check_integral_constant.hpp"
#include "check_type.hpp"
#define CHECK_FALSE(e) BOOST_CHECK_INTEGRAL_CONSTANT(e, false)
#define CHECK_TRUE(e) BOOST_CHECK_INTEGRAL_CONSTANT(e, true)
template<class T>
using type_t = typename T::type;
struct has_type {
using type = char;
};
struct no_type { };
TT_TEST_BEGIN(is_detected)
CHECK_FALSE((::tt::is_detected<type_t, int>::value));
CHECK_TRUE((::tt::is_detected<type_t, has_type>::value));
CHECK_FALSE((::tt::is_detected<type_t, no_type>::value));
#ifndef BOOST_NO_CXX14_VARIABLE_TEMPLATES
CHECK_FALSE((::tt::is_detected_v<type_t, int>));
CHECK_TRUE((::tt::is_detected_v<type_t, has_type>));
CHECK_FALSE((::tt::is_detected_v<type_t, no_type>));
#endif
TT_TEST_END
#else
int main()
{
return 0;
}
#endif