@@ -43,11 +43,11 @@ class Span
43
43
44
44
constexpr Span () : mDataBuf(nullptr ), mDataLen(0 ) {}
45
45
constexpr Span (pointer databuf, size_t datalen) : mDataBuf(databuf), mDataLen(datalen) {}
46
- template <size_t N>
47
- constexpr explicit Span (T (&databuf)[N]) : Span(databuf, N)
46
+ template <class U , size_t N, typename = std:: enable_if_t < sizeof (U) == sizeof (T) && std::is_convertible<U *, T *>::value> >
47
+ constexpr explicit Span (U (&databuf)[N]) : Span(databuf, N)
48
48
{}
49
49
50
- template <class U , size_t N, typename = std::enable_if_t <std::is_same<std:: remove_const_t <T>, std::remove_const_t <U> >::value>>
50
+ template <class U , size_t N, typename = std::enable_if_t <sizeof (U) == sizeof (T) && std::is_convertible<U *, T * >::value>>
51
51
constexpr Span (std::array<U, N> & arr) : mDataBuf(arr.data()), mDataLen(N)
52
52
{}
53
53
@@ -60,14 +60,20 @@ class Span
60
60
}
61
61
62
62
// Allow implicit construction from a Span over a type that matches our
63
- // type, up to const-ness.
64
- template <class U , typename = std::enable_if_t <std::is_same<std::remove_const_t <T>, std::remove_const_t <U>>::value>>
63
+ // type's size, if a pointer to the other type can be treated as a pointer
64
+ // to our type (e.g. other type is same as ours, or is a same-size
65
+ // subclass). The size check is really important to make sure we don't get
66
+ // confused about where our object boundaries are.
67
+ template <class U , typename = std::enable_if_t <sizeof (U) == sizeof (T) && std::is_convertible<U *, T *>::value>>
65
68
constexpr Span (const Span<U> & other) : Span(other.data(), other.size())
66
69
{}
67
70
68
71
// Allow implicit construction from a FixedSpan over a type that matches our
69
- // type, up to const-ness.
70
- template <class U , size_t N, typename = std::enable_if_t <std::is_same<std::remove_const_t <T>, std::remove_const_t <U>>::value>>
72
+ // type's size, if a pointer to the other type can be treated as a pointer
73
+ // to our type (e.g. other type is same as ours, or is a same-size
74
+ // subclass). The size check is really important to make sure we don't get
75
+ // confused about where our object boundaries are.
76
+ template <class U , size_t N, typename = std::enable_if_t <sizeof (U) == sizeof (T) && std::is_convertible<U *, T *>::value>>
71
77
constexpr inline Span (const FixedSpan<U, N> & other);
72
78
73
79
constexpr pointer data () const { return mDataBuf ; }
@@ -169,28 +175,25 @@ class FixedSpan
169
175
//
170
176
// To do that we have a template constructor enabled only when the type
171
177
// passed to it is a pointer type, and that pointer is to a type that
172
- // matches T up to const-ness. Importantly, we do NOT want to allow
173
- // subclasses of T here, because they would have a different size and our
174
- // Span would not work right.
175
- template <
176
- class U ,
177
- typename = std::enable_if_t <std::is_pointer<U>::value &&
178
- std::is_same<std::remove_const_t <T>, std::remove_const_t <std::remove_pointer_t <U>>>::value>>
178
+ // matches T's size and can convert to T*.
179
+ template <class U ,
180
+ typename = std::enable_if_t <std::is_pointer<U>::value && sizeof (std::remove_pointer_t <U>) == sizeof (T) &&
181
+ std::is_convertible<U, T *>::value>>
179
182
constexpr explicit FixedSpan (U databuf) : mDataBuf(databuf)
180
183
{}
181
- template <class U , size_t M, typename = std::enable_if_t <std::is_same<std:: remove_const_t <T>, std::remove_const_t <U> >::value>>
184
+ template <class U , size_t M, typename = std::enable_if_t <sizeof (U) == sizeof (T) && std::is_convertible<U *, T * >::value>>
182
185
constexpr explicit FixedSpan (U (&databuf)[M]) : mDataBuf(databuf)
183
186
{
184
187
static_assert (M >= N, " Passed-in buffer too small for FixedSpan" );
185
188
}
186
189
187
- template <class U , typename = std::enable_if_t <std::is_same<std:: remove_const_t <T>, std::remove_const_t <U> >::value>>
190
+ template <class U , typename = std::enable_if_t <sizeof (U) == sizeof (T) && std::is_convertible<U *, T * >::value>>
188
191
constexpr FixedSpan (std::array<U, N> & arr) : mDataBuf(arr.data())
189
192
{}
190
193
191
194
// Allow implicit construction from a FixedSpan of sufficient size over a
192
- // type that matches our type, up to const-ness .
193
- template <class U , size_t M, typename = std::enable_if_t <std::is_same<std:: remove_const_t <T>, std::remove_const_t <U> >::value>>
195
+ // type that has the same size as ours, as long as the pointers are convertible .
196
+ template <class U , size_t M, typename = std::enable_if_t <sizeof (U) == sizeof (T) && std::is_convertible<U *, T * >::value>>
194
197
constexpr FixedSpan (FixedSpan<U, M> const & other) : mDataBuf(other.data())
195
198
{
196
199
static_assert (M >= N, " Passed-in FixedSpan is smaller than we are" );
0 commit comments