const _Iter* _M_cur;
public:
+ constexpr
explicit
_DestroyGuard(const _Iter& __iter)
: _M_first(__iter), _M_cur(std::__addressof(__iter))
{ }
+ constexpr
void
release() noexcept
{ _M_cur = nullptr; }
+ constexpr
~_DestroyGuard()
{
if (_M_cur != nullptr)
&& is_trivially_destructible_v<iter_value_t<_Iter>>
struct _DestroyGuard<_Iter>
{
+ constexpr
explicit
_DestroyGuard(const _Iter&)
{ }
+ constexpr
void
release() noexcept
{ }
template<__detail::__nothrow_forward_iterator _Iter,
__detail::__nothrow_sentinel<_Iter> _Sent>
requires default_initializable<iter_value_t<_Iter>>
+ _GLIBCXX26_CONSTEXPR
_Iter
operator()(_Iter __first, _Sent __last) const
{
template<__detail::__nothrow_forward_range _Range>
requires default_initializable<range_value_t<_Range>>
+ _GLIBCXX26_CONSTEXPR
borrowed_iterator_t<_Range>
operator()(_Range&& __r) const
{
{
template<__detail::__nothrow_forward_iterator _Iter>
requires default_initializable<iter_value_t<_Iter>>
+ _GLIBCXX26_CONSTEXPR
_Iter
operator()(_Iter __first, iter_difference_t<_Iter> __n) const
{
template<__detail::__nothrow_forward_iterator _Iter,
__detail::__nothrow_sentinel<_Iter> _Sent>
requires default_initializable<iter_value_t<_Iter>>
+ _GLIBCXX26_CONSTEXPR
_Iter
operator()(_Iter __first, _Sent __last) const
{
template<__detail::__nothrow_forward_range _Range>
requires default_initializable<range_value_t<_Range>>
+ _GLIBCXX26_CONSTEXPR
borrowed_iterator_t<_Range>
operator()(_Range&& __r) const
{
{
template<__detail::__nothrow_forward_iterator _Iter>
requires default_initializable<iter_value_t<_Iter>>
+ _GLIBCXX26_CONSTEXPR
_Iter
operator()(_Iter __first, iter_difference_t<_Iter> __n) const
{
__detail::__nothrow_forward_iterator _Out,
__detail::__nothrow_sentinel<_Out> _OSent>
requires constructible_from<iter_value_t<_Out>, iter_reference_t<_Iter>>
+ _GLIBCXX26_CONSTEXPR
uninitialized_copy_result<_Iter, _Out>
operator()(_Iter __ifirst, _ISent __ilast,
_Out __ofirst, _OSent __olast) const
template<input_range _IRange, __detail::__nothrow_forward_range _ORange>
requires constructible_from<range_value_t<_ORange>,
range_reference_t<_IRange>>
+ _GLIBCXX26_CONSTEXPR
uninitialized_copy_result<borrowed_iterator_t<_IRange>,
borrowed_iterator_t<_ORange>>
operator()(_IRange&& __inr, _ORange&& __outr) const
template<input_iterator _Iter, __detail::__nothrow_forward_iterator _Out,
__detail::__nothrow_sentinel<_Out> _Sent>
requires constructible_from<iter_value_t<_Out>, iter_reference_t<_Iter>>
+ _GLIBCXX26_CONSTEXPR
uninitialized_copy_n_result<_Iter, _Out>
operator()(_Iter __ifirst, iter_difference_t<_Iter> __n,
_Out __ofirst, _Sent __olast) const
__detail::__nothrow_sentinel<_Out> _OSent>
requires constructible_from<iter_value_t<_Out>,
iter_rvalue_reference_t<_Iter>>
+ _GLIBCXX26_CONSTEXPR
uninitialized_move_result<_Iter, _Out>
operator()(_Iter __ifirst, _ISent __ilast,
_Out __ofirst, _OSent __olast) const
template<input_range _IRange, __detail::__nothrow_forward_range _ORange>
requires constructible_from<range_value_t<_ORange>,
range_rvalue_reference_t<_IRange>>
+ _GLIBCXX26_CONSTEXPR
uninitialized_move_result<borrowed_iterator_t<_IRange>,
borrowed_iterator_t<_ORange>>
operator()(_IRange&& __inr, _ORange&& __outr) const
__detail::__nothrow_sentinel<_Out> _Sent>
requires constructible_from<iter_value_t<_Out>,
iter_rvalue_reference_t<_Iter>>
+ _GLIBCXX26_CONSTEXPR
uninitialized_move_n_result<_Iter, _Out>
operator()(_Iter __ifirst, iter_difference_t<_Iter> __n,
_Out __ofirst, _Sent __olast) const
template<__detail::__nothrow_forward_iterator _Iter,
__detail::__nothrow_sentinel<_Iter> _Sent, typename _Tp>
requires constructible_from<iter_value_t<_Iter>, const _Tp&>
+ _GLIBCXX26_CONSTEXPR
_Iter
operator()(_Iter __first, _Sent __last, const _Tp& __x) const
{
template<__detail::__nothrow_forward_range _Range, typename _Tp>
requires constructible_from<range_value_t<_Range>, const _Tp&>
+ _GLIBCXX26_CONSTEXPR
borrowed_iterator_t<_Range>
operator()(_Range&& __r, const _Tp& __x) const
{
{
template<__detail::__nothrow_forward_iterator _Iter, typename _Tp>
requires constructible_from<iter_value_t<_Iter>, const _Tp&>
+ _GLIBCXX26_CONSTEXPR
_Iter
operator()(_Iter __first, iter_difference_t<_Iter> __n,
const _Tp& __x) const
}
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
+
#endif // concepts
#endif // C++20
#endif // _RANGES_UNINITIALIZED_H
#endif
template<typename _T1>
+ _GLIBCXX26_CONSTEXPR
inline void
_Construct_novalue(_T1* __p)
{ ::new(static_cast<void*>(__p)) _T1; }
* Like std::copy, but does not require an initialized output range.
*/
template<typename _InputIterator, typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline _ForwardIterator
uninitialized_copy(_InputIterator __first, _InputIterator __last,
_ForwardIterator __result)
using _Src = decltype(std::__niter_base(__first));
using _ValT = typename iterator_traits<_ForwardIterator>::value_type;
+#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26
+ if consteval {
+ return std::__do_uninit_copy(__first, __last, __result);
+ }
+#endif
if constexpr (!__is_trivially_constructible(_ValT, decltype(*__first)))
return std::__do_uninit_copy(__first, __last, __result);
else if constexpr (__memcpyable<_Dest, _Src>::__value)
* Like std::fill, but does not require an initialized output range.
*/
template<typename _ForwardIterator, typename _Tp>
+ _GLIBCXX26_CONSTEXPR
inline void
uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last,
const _Tp& __x)
#if __cplusplus >= 201103L
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wc++17-extensions"
+#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26
+ if consteval {
+ return std::__do_uninit_fill(__first, __last, __x);
+ }
+#endif
if constexpr (__is_byte<_ValueType>::__value)
if constexpr (is_same<_ValueType, _Tp>::value
|| is_integral<_Tp>::value)
* Like std::fill_n, but does not require an initialized output range.
*/
template<typename _ForwardIterator, typename _Size, typename _Tp>
+ _GLIBCXX26_CONSTEXPR
inline _ForwardIterator
uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x)
{
_ValueType;
#if __cplusplus >= 201103L
+#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26
+ if consteval {
+ return std::__do_uninit_fill_n(__first, __n, __x);
+ }
+#endif
if constexpr (__is_byte<_ValueType>::__value)
if constexpr (is_integral<_Tp>::value)
if constexpr (is_integral<_Size>::value)
struct __uninitialized_default_1
{
template<typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
static void
__uninit_default(_ForwardIterator __first, _ForwardIterator __last)
{
struct __uninitialized_default_1<true>
{
template<typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
static void
__uninit_default(_ForwardIterator __first, _ForwardIterator __last)
{
// __uninitialized_default
// Fills [first, last) with value-initialized value_types.
template<typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline void
__uninitialized_default(_ForwardIterator __first,
_ForwardIterator __last)
struct __uninitialized_default_novalue_1
{
template<typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
static void
__uninit_default_novalue(_ForwardIterator __first,
_ForwardIterator __last)
struct __uninitialized_default_novalue_1<true>
{
template<typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
static void
__uninit_default_novalue(_ForwardIterator, _ForwardIterator)
{
struct __uninitialized_default_novalue_n_1
{
template<typename _ForwardIterator, typename _Size>
+ _GLIBCXX26_CONSTEXPR
static _ForwardIterator
__uninit_default_novalue_n(_ForwardIterator __first, _Size __n)
{
struct __uninitialized_default_novalue_n_1<true>
{
template<typename _ForwardIterator, typename _Size>
+ _GLIBCXX26_CONSTEXPR
static _ForwardIterator
__uninit_default_novalue_n(_ForwardIterator __first, _Size __n)
{ return std::next(__first, __n); }
// __uninitialized_default_novalue
// Fills [first, last) with default-initialized value_types.
template<typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline void
__uninitialized_default_novalue(_ForwardIterator __first,
_ForwardIterator __last)
// __uninitialized_default_novalue_n
// Fills [first, first + n) with default-initialized value_types.
template<typename _ForwardIterator, typename _Size>
+ _GLIBCXX26_CONSTEXPR
inline _ForwardIterator
__uninitialized_default_novalue_n(_ForwardIterator __first, _Size __n)
{
template<typename _InputIterator, typename _Size,
typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
_ForwardIterator
__uninitialized_copy_n(_InputIterator __first, _Size __n,
_ForwardIterator __result, input_iterator_tag)
template<typename _RandomAccessIterator, typename _Size,
typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline _ForwardIterator
__uninitialized_copy_n(_RandomAccessIterator __first, _Size __n,
_ForwardIterator __result,
template<typename _InputIterator, typename _Size,
typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
pair<_InputIterator, _ForwardIterator>
__uninitialized_copy_n_pair(_InputIterator __first, _Size __n,
_ForwardIterator __result, input_iterator_tag)
template<typename _RandomAccessIterator, typename _Size,
typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline pair<_RandomAccessIterator, _ForwardIterator>
__uninitialized_copy_n_pair(_RandomAccessIterator __first, _Size __n,
_ForwardIterator __result,
* Like copy_n(), but does not require an initialized output range.
*/
template<typename _InputIterator, typename _Size, typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline _ForwardIterator
uninitialized_copy_n(_InputIterator __first, _Size __n,
_ForwardIterator __result)
/// @cond undocumented
template<typename _InputIterator, typename _Size, typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline pair<_InputIterator, _ForwardIterator>
__uninitialized_copy_n_pair(_InputIterator __first, _Size __n,
_ForwardIterator __result)
* @since C++17
*/
template <typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline void
uninitialized_default_construct(_ForwardIterator __first,
_ForwardIterator __last)
* @since C++17
*/
template <typename _ForwardIterator, typename _Size>
+ _GLIBCXX26_CONSTEXPR
inline _ForwardIterator
uninitialized_default_construct_n(_ForwardIterator __first, _Size __count)
{
* @since C++17
*/
template <typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline void
uninitialized_value_construct(_ForwardIterator __first,
_ForwardIterator __last)
* @since C++17
*/
template <typename _ForwardIterator, typename _Size>
+ _GLIBCXX26_CONSTEXPR
inline _ForwardIterator
uninitialized_value_construct_n(_ForwardIterator __first, _Size __count)
{
* @since C++17
*/
template <typename _InputIterator, typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline _ForwardIterator
uninitialized_move(_InputIterator __first, _InputIterator __last,
_ForwardIterator __result)
* @since C++17
*/
template <typename _InputIterator, typename _Size, typename _ForwardIterator>
+ _GLIBCXX26_CONSTEXPR
inline pair<_InputIterator, _ForwardIterator>
uninitialized_move_n(_InputIterator __first, _Size __count,
_ForwardIterator __result)
ftms = {
name = raw_memory_algorithms;
+ values = {
+ v = 202411;
+ cxxmin = 26;
+ extra_cond = "__cpp_constexpr >= 202406L";
+ };
values = {
v = 201606;
cxxmin = 17;
#undef __glibcxx_want_gcd_lcm
#if !defined(__cpp_lib_raw_memory_algorithms)
-# if (__cplusplus >= 201703L)
+# if (__cplusplus > 202302L) && (__cpp_constexpr >= 202406L)
+# define __glibcxx_raw_memory_algorithms 202411L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_raw_memory_algorithms)
+# define __cpp_lib_raw_memory_algorithms 202411L
+# endif
+# elif (__cplusplus >= 201703L)
# define __glibcxx_raw_memory_algorithms 201606L
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_raw_memory_algorithms)
# define __cpp_lib_raw_memory_algorithms 201606L
template <class T> T* addressof(T&) noexcept;
#endif
template <class InputIterator, class ForwardIterator>
+#if __cplusplus >= 202400L
+ constexpr
+#endif
ForwardIterator
uninitialized_copy(InputIterator first, InputIterator last,
ForwardIterator result);
#if __cplusplus >= 201103L
template <class InputIterator, class Size, class ForwardIterator>
+#if __cplusplus >= 202400L
+ constexpr
+#endif
ForwardIterator
uninitialized_copy_n(InputIterator first, Size n, ForwardIterator result);
#endif
template <class ForwardIterator, class T>
+#if __cplusplus >= 202400L
+ constexpr
+#endif
void uninitialized_fill(ForwardIterator first, ForwardIterator last,
const T& x);
template <class ForwardIterator, class Size, class T>
+#if __cplusplus >= 202400L
+ constexpr
+#endif
void uninitialized_fill_n(ForwardIterator first, Size n, const T& x);
#if __cplusplus >= 201103L
--- /dev/null
+// { dg-do compile { target c++17 } }
+// { dg-add-options no_pch }
+
+#include <memory>
+
+#ifndef __cpp_lib_raw_memory_algorithms
+# error "Feature-test macro for raw memory algorithms missing"
+#elif __cplusplus > 202302L
+# if __cpp_lib_raw_memory_algorithms < 202411L
+# error "Feature-test macro for raw memory algorithms has wrong value"
+# endif
+#elif __cpp_lib_raw_memory_algorithms < 201606L
+# error "Feature-test macro for raw memory algorithms has wrong value"
+#endif
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
+#include <vector>
+
+template<typename T>
+constexpr
+bool
+test01_impl(std::vector<T> input)
+{
+ static_assert(std::copy_constructible<T>);
+ static_assert(std::equality_comparable<T>);
+
+ const std::size_t input_size = input.size();
+ std::allocator<T> alloc;
+ T* ptr = alloc.allocate(input_size);
+
+ std::uninitialized_copy(input.begin(), input.end(), ptr);
+ if (!std::equal(input.begin(), input.end(), ptr, ptr + input_size))
+ return false;
+ std::destroy(ptr, ptr + input_size);
+
+ std::uninitialized_copy_n(input.begin(), input_size, ptr);
+ if (!std::equal(input.begin(), input.end(), ptr, ptr + input_size))
+ return false;
+ std::destroy_n(ptr, input_size);
+
+ std::span<T> output(ptr, ptr + input_size);
+ std::ranges::uninitialized_copy(input, output);
+ if (!std::ranges::equal(input, output))
+ return false;
+ std::ranges::destroy(output);
+
+ std::ranges::uninitialized_copy_n(input.begin(), input_size, ptr, ptr + input_size);
+ if (!std::ranges::equal(input.begin(), input.end(), ptr, ptr + input_size))
+ return false;
+ std::ranges::destroy_n(ptr, input_size);
+
+ alloc.deallocate(ptr, input_size);
+ return true;
+}
+
+constexpr
+bool
+test01()
+{
+ return
+ test01_impl<char>({'a', 'b', 'c'}) &&
+ test01_impl<int>({1, 2, 3, 4}) &&
+ test01_impl<double>({1.0, 2.0, 3.0, 4.0}) &&
+ test01_impl<std::string>({"a", "b", "cc", "dddd", "eeeeeeeeeeeeeeee"}) &&
+ test01_impl<std::vector<int>>({ {0}, {0, 1}, {0, 1, 2}});
+}
+
+static_assert(test01());
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
+#include <vector>
+
+template<typename T>
+constexpr
+bool
+test01_impl()
+{
+ static_assert(std::default_initializable<T>);
+ static_assert(std::equality_comparable<T>);
+
+ constexpr std::size_t size = 42;
+ std::allocator<T> alloc;
+ T* ptr = alloc.allocate(size);
+
+ auto check = [&]() -> bool
+ {
+ if constexpr (!std::is_trivially_default_constructible_v<T>)
+ return std::all_of(ptr, ptr + size, [](auto &&x) { return x == T(); });
+ else
+ return true;
+ };
+
+ std::uninitialized_default_construct(ptr, ptr + size);
+ if (!check())
+ return false;
+ std::destroy(ptr, ptr + size);
+
+ std::uninitialized_default_construct_n(ptr, size);
+ if (!check())
+ return false;
+ std::destroy_n(ptr, size);
+
+ std::span<T> storage(ptr, ptr + size);
+ std::ranges::uninitialized_default_construct(storage);
+ if (!check())
+ return false;
+ std::ranges::destroy(storage);
+
+ std::ranges::uninitialized_default_construct_n(ptr, size);
+ if (!check())
+ return false;
+ std::ranges::destroy_n(ptr, size);
+
+ alloc.deallocate(ptr, size);
+ return true;
+}
+
+constexpr
+bool
+test01()
+{
+ return
+ test01_impl<char>() &&
+ test01_impl<int>() &&
+ test01_impl<double>() &&
+ test01_impl<std::string>() &&
+ test01_impl<std::vector<int>>() &&
+ test01_impl<std::unique_ptr<int>>();
+}
+
+static_assert(test01());
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
+#include <vector>
+
+template<typename T, typename U = T>
+constexpr
+bool
+test01_impl(const U& value = U())
+{
+ static_assert(std::constructible_from<T, U>);
+ //static_assert(std::equality_comparable_with<T, U>); // unique_ptr fails with nullptr_t
+
+ constexpr std::size_t size = 42;
+ std::allocator<T> alloc;
+ T* ptr = alloc.allocate(size);
+
+ auto check = [&]() -> bool
+ {
+ return std::all_of(ptr, ptr + size, [&](auto &&x) { return x == value; });
+ };
+
+ std::uninitialized_fill(ptr, ptr + size, value);
+ if (!check())
+ return false;
+ std::destroy(ptr, ptr + size);
+
+ std::uninitialized_fill_n(ptr, size, value);
+ if (!check())
+ return false;
+ std::destroy_n(ptr, size);
+
+ std::span<T> storage(ptr, ptr + size);
+ std::ranges::uninitialized_fill(storage, value);
+ if (!check())
+ return false;
+ std::ranges::destroy(storage);
+
+ std::ranges::uninitialized_fill_n(ptr, size, value);
+ if (!check())
+ return false;
+ std::ranges::destroy_n(ptr, size);
+
+ alloc.deallocate(ptr, size);
+ return true;
+}
+
+constexpr
+bool
+test01()
+{
+ return
+ test01_impl<char>('\0') &&
+ test01_impl<char>('x') &&
+ test01_impl<int>(0) &&
+ test01_impl<int>(42) &&
+ test01_impl<double>(3.14) &&
+ test01_impl<std::string>() &&
+ test01_impl<std::string>(std::string("test")) &&
+ test01_impl<std::vector<int>>() &&
+ test01_impl<std::vector<int>>({1, 2, 3, 4}) &&
+ test01_impl<std::unique_ptr<int>>(nullptr);
+}
+
+static_assert(test01());
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
+#include <vector>
+
+template<typename T>
+constexpr
+bool
+test01_impl(std::vector<T> input)
+{
+ static_assert(std::move_constructible<T>);
+ static_assert(std::equality_comparable<T>);
+
+ const std::size_t input_size = input.size();
+ std::allocator<T> alloc;
+ T* ptr = alloc.allocate(input_size);
+
+ std::uninitialized_move(input.begin(), input.end(), ptr);
+ std::destroy(ptr, ptr + input_size);
+
+ std::uninitialized_move_n(input.begin(), input_size, ptr);
+ std::destroy_n(ptr, input_size);
+
+ std::span<T> output(ptr, ptr + input_size);
+ std::ranges::uninitialized_move(input, output);
+ std::ranges::destroy(output);
+
+ std::ranges::uninitialized_move_n(input.begin(), input_size, ptr, ptr + input_size);
+ std::ranges::destroy_n(ptr, input_size);
+
+ alloc.deallocate(ptr, input_size);
+ return true;
+}
+
+constexpr
+bool
+test01()
+{
+ return
+ test01_impl<char>({'a', 'b', 'c'}) &&
+ test01_impl<int>({1, 2, 3, 4}) &&
+ test01_impl<double>({1.0, 2.0, 3.0, 4.0}) &&
+ test01_impl<std::string>({"a", "b", "cc", "dddd", "eeeeeeeeeeeeeeee"}) &&
+ test01_impl<std::vector<int>>({ {0}, {0, 1}, {0, 1, 2}}) &&
+ test01_impl<std::unique_ptr<int>>(std::vector<std::unique_ptr<int>>(10));
+}
+
+static_assert(test01());
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
+#include <vector>
+
+template<typename T>
+constexpr
+bool
+test01_impl()
+{
+ static_assert(std::default_initializable<T>);
+ static_assert(std::equality_comparable<T>);
+
+ constexpr std::size_t size = 42;
+ std::allocator<T> alloc;
+ T* ptr = alloc.allocate(size);
+
+ auto check = [&]() -> bool
+ {
+ return std::all_of(ptr, ptr + size, [](auto &&x) { return x == T(); });
+ };
+
+ std::uninitialized_value_construct(ptr, ptr + size);
+ if (!check())
+ return false;
+ std::destroy(ptr, ptr + size);
+
+ std::uninitialized_value_construct_n(ptr, size);
+ if (!check())
+ return false;
+ std::destroy_n(ptr, size);
+
+ std::span<T> storage(ptr, ptr + size);
+ std::ranges::uninitialized_value_construct(storage);
+ if (!check())
+ return false;
+ std::ranges::destroy(storage);
+
+ std::ranges::uninitialized_value_construct_n(ptr, size);
+ if (!check())
+ return false;
+ std::ranges::destroy_n(ptr, size);
+
+ alloc.deallocate(ptr, size);
+ return true;
+}
+
+constexpr
+bool
+test01()
+{
+ return
+ test01_impl<char>() &&
+ test01_impl<int>() &&
+ test01_impl<double>() &&
+ test01_impl<std::string>() &&
+ test01_impl<std::vector<int>>() &&
+ test01_impl<std::unique_ptr<int>>();
+}
+
+static_assert(test01());