Span: use static assert to kill copy construction from an incompatible span type.

Copy construction between Span of compatible type is allowed to fulfil the use
case Span<T> -> Span<const T>. This is achieved by a templated copy constructor
like constructor.

In p0122, the overload is discarded from the constructor set if the ElementType
of the Span in input is not convertible into the ElementType of the Span being
constructed.

To discard function overload, SFINAE has to be used which polutes the documentation
and make the code harder to read and maintain.

Unlike p0122, our Span class doesn't exposes (yet) functions with default argument
or functions that convert container in input into span the only overload with the
a single parameter that we exposes are:
- template<size_t N> Span(ElementType (&element)[N])
- Span(const Span& other): <- generated by the compiler.

For both of this functions we expect exact match and their resolution should not
interfere with the constructor that converts from another type of Span.

As a result it is possible to rely solely on C++ default resolution rules as we
won't hit cases were constructors convert from another type (std::array, std
container, span) and raise an error with a static assert if the element type
can't be converted.

If another copy - conversion - constructor is added then SFINAE has to be
reintroduced.
pull/7828/head
Vincent Coubard 2018-08-24 11:10:17 +01:00
parent d5051a8ca7
commit af69e1fb8b
1 changed files with 16 additions and 23 deletions

View File

@ -45,14 +45,6 @@ public:
static const bool value = sizeof(true_type) == sizeof(sink(generator()));
};
template<bool Condition, typename ResultType = void>
struct enable_if;
template<typename ResultType>
struct enable_if<true, ResultType> {
typedef ResultType type;
};
}
/**
@ -309,13 +301,14 @@ struct Span {
* @note OtherElementType(*)[] should be convertible to ElementType(*)[].
*/
template<typename OtherElementType>
Span(
const Span<OtherElementType, Extent> &other,
typename span_detail::enable_if<
span_detail::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value
>::type* = 0
):
_data(other.data()) { }
Span(const Span<OtherElementType, Extent> &other):
_data(other.data())
{
MBED_STATIC_ASSERT(
(span_detail::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value),
"OtherElementType(*)[] should be convertible to ElementType (*)[]"
);
}
/**
* Return the size of the sequence viewed.
@ -499,7 +492,6 @@ private:
*/
template<typename ElementType>
struct Span<ElementType, SPAN_DYNAMIC_EXTENT> {
/**
* Type of the element contained
*/
@ -598,13 +590,14 @@ struct Span<ElementType, SPAN_DYNAMIC_EXTENT> {
* @note OtherElementType(*)[] should be convertible to ElementType(*)[].
*/
template<typename OtherElementType, ptrdiff_t OtherExtent>
Span(
const Span<OtherElementType, OtherExtent> &other,
typename span_detail::enable_if<
span_detail::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value
>::type* = NULL
):
_data(other.data()), _size(other.size()) { }
Span(const Span<OtherElementType, OtherExtent> &other):
_data(other.data()), _size(other.size())
{
MBED_STATIC_ASSERT(
(span_detail::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value),
"OtherElementType(*)[] should be convertible to ElementType (*)[]"
);
}
/**
* Return the size of the array viewed.