Skip to content

Commit

Permalink
Implement LWG-3545 std::pointer_traits should be SFINAE-friendly (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
frederick-vs-ja authored Dec 6, 2022
1 parent 214e014 commit 0a1c6c4
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 14 deletions.
32 changes: 18 additions & 14 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -210,16 +210,6 @@ struct _Replace_first_parameter<_Newfirst, _Ty<_First, _Rest...>> { // given _Ty
using type = _Ty<_Newfirst, _Rest...>;
};

template <class _Ty, class = void>
struct _Get_element_type {
using type = typename _Get_first_parameter<_Ty>::type;
};

template <class _Ty>
struct _Get_element_type<_Ty, void_t<typename _Ty::element_type>> {
using type = typename _Ty::element_type;
};

template <class _Ty, class = void>
struct _Get_ptr_difference_type {
using type = ptrdiff_t;
Expand Down Expand Up @@ -281,23 +271,37 @@ void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_construc
::new (_Voidify_iter(_STD addressof(_Obj))) _Ty;
}

_EXPORT_STD template <class _Ty>
struct pointer_traits {
template <class _Ty, class _Elem>
struct _Ptr_traits_base {
using pointer = _Ty;
using element_type = typename _Get_element_type<_Ty>::type;
using element_type = _Elem;
using difference_type = typename _Get_ptr_difference_type<_Ty>::type;

template <class _Other>
using rebind = typename _Get_rebind_alias<_Ty, _Other>::type;

using _Reftype = conditional_t<is_void_v<element_type>, char, element_type>&;
using _Reftype = conditional_t<is_void_v<_Elem>, char, _Elem>&;

_NODISCARD static _CONSTEXPR20 pointer pointer_to(_Reftype _Val) noexcept(
noexcept(_Ty::pointer_to(_Val))) /* strengthened */ { // Per LWG-3454
return _Ty::pointer_to(_Val);
}
};

template <class, class = void, class = void>
struct _Ptr_traits_sfinae_layer {};

template <class _Ty, class _Uty>
struct _Ptr_traits_sfinae_layer<_Ty, _Uty, void_t<typename _Get_first_parameter<_Ty>::type>>
: _Ptr_traits_base<_Ty, typename _Get_first_parameter<_Ty>::type> {};

template <class _Ty>
struct _Ptr_traits_sfinae_layer<_Ty, void_t<typename _Ty::element_type>, void>
: _Ptr_traits_base<_Ty, typename _Ty::element_type> {};

_EXPORT_STD template <class _Ty>
struct pointer_traits : _Ptr_traits_sfinae_layer<_Ty> {};

template <class _Ty>
struct pointer_traits<_Ty*> {
using pointer = _Ty*;
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ tests\LWG3146_excessive_unwrapping_ref_cref
tests\LWG3234_math_special_overloads
tests\LWG3422_seed_seq_ctors
tests\LWG3480_directory_iterator_range
tests\LWG3545_pointer_traits_sfinae
tests\LWG3610_iota_view_size_and_integer_class
tests\P0019R8_atomic_ref
tests\P0024R2_parallel_algorithms_adjacent_difference
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/LWG3545_pointer_traits_sfinae/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_matrix.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <cstddef>
#include <memory>
#include <type_traits>

using namespace std;

#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__);

template <class, class = void>
constexpr bool has_memtype_element_type = false;

template <class T>
constexpr bool has_memtype_element_type<T, void_t<typename T::element_type>> = true;

template <class, class = void>
constexpr bool has_memtype_pointer = false;

template <class T>
constexpr bool has_memtype_pointer<T, void_t<typename T::pointer>> = true;

template <class, class = void>
constexpr bool has_memtype_difference_type = false;

template <class T>
constexpr bool has_memtype_difference_type<T, void_t<typename T::difference_type>> = true;

STATIC_ASSERT(!has_memtype_element_type<pointer_traits<int>>);
STATIC_ASSERT(!has_memtype_pointer<pointer_traits<int>>);
STATIC_ASSERT(!has_memtype_difference_type<pointer_traits<int>>);

struct LackElementType {
using pointer = int;
using difference_type = int;
template <class>
using rebind = int;
};

STATIC_ASSERT(!has_memtype_element_type<pointer_traits<LackElementType>>);
STATIC_ASSERT(!has_memtype_pointer<pointer_traits<LackElementType>>);
STATIC_ASSERT(!has_memtype_difference_type<pointer_traits<LackElementType>>);

struct OnlyElementType {
using element_type = void;
};

STATIC_ASSERT(has_memtype_element_type<pointer_traits<OnlyElementType>>);
STATIC_ASSERT(has_memtype_pointer<pointer_traits<OnlyElementType>>);
STATIC_ASSERT(has_memtype_difference_type<pointer_traits<OnlyElementType>>);

STATIC_ASSERT(is_same_v<pointer_traits<OnlyElementType>::element_type, void>);
STATIC_ASSERT(is_same_v<pointer_traits<OnlyElementType>::pointer, OnlyElementType>);
STATIC_ASSERT(is_same_v<pointer_traits<OnlyElementType>::difference_type, ptrdiff_t>);

template <class I>
struct Templated {
using difference_type = I;
};

STATIC_ASSERT(has_memtype_element_type<pointer_traits<Templated<char>>>);
STATIC_ASSERT(has_memtype_pointer<pointer_traits<Templated<char>>>);
STATIC_ASSERT(has_memtype_difference_type<pointer_traits<Templated<char>>>);

STATIC_ASSERT(is_same_v<pointer_traits<Templated<char>>::element_type, char>);
STATIC_ASSERT(is_same_v<pointer_traits<Templated<char>>::pointer, Templated<char>>);
STATIC_ASSERT(is_same_v<pointer_traits<Templated<char>>::difference_type, char>);

template <class I, size_t N = sizeof(I)>
struct BadTemplated {
using difference_type = I;
};

STATIC_ASSERT(!has_memtype_element_type<pointer_traits<BadTemplated<int>>>);
STATIC_ASSERT(!has_memtype_pointer<pointer_traits<BadTemplated<int>>>);
STATIC_ASSERT(!has_memtype_difference_type<pointer_traits<BadTemplated<int>>>);

template <class T>
struct CheckPriority {
using element_type = T[42];
};

STATIC_ASSERT(has_memtype_element_type<pointer_traits<CheckPriority<char>>>);
STATIC_ASSERT(has_memtype_pointer<pointer_traits<CheckPriority<char>>>);
STATIC_ASSERT(has_memtype_difference_type<pointer_traits<CheckPriority<char>>>);

STATIC_ASSERT(is_same_v<pointer_traits<CheckPriority<char>>::element_type, char[42]>);
STATIC_ASSERT(is_same_v<pointer_traits<CheckPriority<char>>::pointer, CheckPriority<char>>);
STATIC_ASSERT(is_same_v<pointer_traits<CheckPriority<char>>::difference_type, ptrdiff_t>);

int main() {} // COMPILE-ONLY

0 comments on commit 0a1c6c4

Please sign in to comment.