-
Notifications
You must be signed in to change notification settings - Fork 37
Open
Description
I'm trying to create strong std::vector<std::string> type implicitly convertible to strong std::span<const std::vector> type.
STL example
const std::vector<std::string> foo = { "abc", "cde", "efg" };
const std::span<const std::string> bar = foo; // Implicitly convertible even when passing vector to function accepting spans only.
std::vector<std::string> dest;
std::copy( bar.begin(), bar.end(), std::back_inserter( dest ) ); // OK
std::ranges::copy( bar, std::back_inserter( dest ) ); // Seems OK, didn't tried C:Strong example
Foreward some of our custom modifiers
template<class T>
concept SpanLike = requires( T t, const T ct ) {
typename T::size_type;
typename T::value_type;
typename T::reference;
ct.subspan( typename T::size_type(), typename T::size_type() );
{ ct.empty() } -> std::same_as<bool>;
{ ct.front() } -> std::same_as<typename T::reference>;
{ ct.back() } -> std::same_as<typename T::reference>;
};
template<class T>
concept StrongSpanLike = strong::is_strong_type<T>::value && SpanLike<strong::underlying_type_t<T>>;
class StdSpan {
public:
template<StrongSpanLike StrongSpan>
class modifier
: public strong::range::modifier<StrongSpan>,
public strong::indexed<typename strong::underlying_type_t<StrongSpan>::size_type>::template modifier<StrongSpan> {
using underlying = strong::underlying_type_t<StrongSpan>;
using value_type = typename underlying::value_type;
using size_type = typename underlying::size_type;
using reference = typename underlying::reference;
public:
/// std::span::subspan(size_type, size_type) const
[[nodiscard]] constexpr StrongSpan subspan( size_type Offset, size_type Count = std::dynamic_extent ) const
noexcept( noexcept( std::declval<const underlying &>().subspan( size_type(), size_type() ) ) )
{
const auto &self = static_cast<const StrongSpan &>( *this );
return StrongSpan { value_of( self ).subspan( Offset, Count ) };
}
/// std::span::empty() const
[[nodiscard]] constexpr bool empty() const noexcept( noexcept( std::declval<const underlying &>().empty() ) )
{
const auto &self = static_cast<const StrongSpan &>( *this );
return value_of( self ).empty();
}
/// std::span::front() const
[[nodiscard]] constexpr reference front() const
noexcept( noexcept( std::declval<const underlying &>().front() ) )
{
const auto &self = static_cast<const StrongSpan &>( *this );
return value_of( self ).front();
}
/// std::span::back() const
[[nodiscard]] constexpr reference back() const noexcept( noexcept( std::declval<const underlying &>().back() ) )
{
const auto &self = static_cast<const StrongSpan &>( *this );
return value_of( self ).back();
}
};
};template<class T>
concept VectorLike = requires( T t, const T ct ) {
typename T::size_type;
typename T::reference;
typename T::const_reference;
{ ct.empty() } -> std::same_as<bool>;
{ t.front() } -> std::same_as<typename T::reference>;
{ ct.front() } -> std::same_as<typename T::const_reference>;
{ t.back() } -> std::same_as<typename T::reference>;
{ ct.back() } -> std::same_as<typename T::const_reference>;
t.reserve( typename T::size_type() );
};
template<class T>
concept StrongVectorLike = strong::is_strong_type<T>::value && VectorLike<strong::underlying_type_t<T>>;
class StdVector {
public:
template<StrongVectorLike T>
class modifier : public strong::default_constructible::modifier<T>,
public strong::equality::modifier<T>,
public strong::range::modifier<T>,
public strong::indexed<typename strong::underlying_type_t<T>::size_type>::template modifier<T> {
using underlying = strong::underlying_type_t<T>;
using size_type = typename underlying::size_type;
using reference = typename underlying::reference;
using const_reference = typename underlying::const_reference;
public:
/// std::vector::empty().
[[nodiscard]] constexpr bool empty() const noexcept( noexcept( std::declval<underlying &>().empty() ) )
{
const auto &self = static_cast<const T &>( *this );
return value_of( self ).empty();
}
/// std::vector::front() const;
[[nodiscard]] constexpr const_reference front() const
noexcept( noexcept( std::declval<const underlying &>().front() ) )
{
const auto &self = static_cast<const T &>( *this );
return value_of( self ).front();
}
/// std::vector::front();
[[nodiscard]] constexpr reference front() noexcept( noexcept( std::declval<underlying &>().front() ) )
{
auto &self = static_cast<T &>( *this );
return value_of( self ).front();
}
/// std::vector::back() const;
[[nodiscard]] constexpr const_reference back() const
noexcept( noexcept( std::declval<const underlying &>().back() ) )
{
const auto &self = static_cast<const T &>( *this );
return value_of( self ).back();
}
/// std::vector::back();
[[nodiscard]] constexpr reference back() noexcept( noexcept( std::declval<underlying &>().back() ) )
{
auto &self = static_cast<T &>( *this );
return value_of( self ).back();
}
/// std::vector::reserve()
constexpr void
reserve( size_type new_cap ) noexcept( noexcept( std::declval<underlying &>().reserve( size_type() ) ) )
{
auto &self = static_cast<T &>( *this );
value_of( self ).reserve( new_cap );
}
/// std::back_inserter(underlying container).
[[nodiscard]] constexpr std::back_insert_iterator<underlying> back_inserter()
{
auto &self = static_cast<T &>( *this );
return std::back_inserter( value_of( self ) );
}
/// std::vector::emplace_back(...)
template<class... Args>
void emplace_back( Args &&...args )
{
auto &self = static_cast<T &>( *this );
value_of( self ).emplace_back( std::forward<Args>( args )... );
}
};
};Now types:
using VectorViewType = strong::type<std::span<const std::string>, struct VectorViewTypeTag_, StdSpan>;
using VectorType = strong::type<std::vector<std::string>, struct VectorTypeTag_, strong::implicitly_convertible_to<VectorViewType>, StdVector>;And usage example:
VectorType foo{ "abc", "cde", "efg" };
VectorViewType bar{ foo };
VectorType dest;
std::copy( bar.begin(), bar.end(), dest.back_inserter() );
// v14 - OK,
// v15 - compile error not really interesting which one because:
// main@13cd075b:
// error: implicit instantiation of undefined template 'strong::range::modifier<strong::type<std::span<const std::string>, VectorViewTypeTag_, StdSpan>>'
std::ranges::copy( bar, dest.back_inserter() ); // Didn't tried, expecting same error here C:Complete (a bit redacted) error output:
Span.hpp:36:18: error: implicit instantiation of undefined template 'strong::range::modifier<strong::type<std::span<const std::string>, VectorViewTag_, StdSpan>>'
36 | : public strong::range::modifier<StrongSpan>,
| ^
include/strong_type/type.hpp:66:21: note: in instantiation of template class 'StdSpan::modifier<strong::type<std::span<const std::string>, VectorViewTag_, StdSpan>>' requested here
66 | class type : public modifier<M, type<T, Tag, M...>> ... {
| ^
include/strong_type/implicitly_convertible_to.hpp:33:21: note: in instantiation of template class 'strong::type<std::span<const std::string>, VectorViewTag_, StdSpan>' requested here
33 | void_t<decltype(static_cast<D>(std::declval<const T&>()))>
| ^
include/strong_type/implicitly_convertible_to.hpp:49:23: note: during template argument deduction for class template partial specialization 'implicit_converter<strong::type<T, Tag, Ms...>, D, void_t<decltype(static_cast<D>(std::declval<const T &>()))>>' [with T = std::vector<std::string>, Tag = VectorTypeTag_, Ms = <strong::implicitly_convertible_to<strong::type<std::span<const std::string>, VectorViewTag_, StdSpan>>, StdVector>, D = strong::type<std::span<const std::string>, VectorViewTag_, StdSpan>]
49 | struct modifier : impl::implicit_converter<T, Ts>...
| ^
include/strong_type/implicitly_convertible_to.hpp:49:23: note: in instantiation of template class 'strong::impl::implicit_converter<strong::type<std::vector<std::string>, VectorTypeTag_, strong::implicitly_convertible_to<strong::type<std::span<const std::string>, VectorViewTag_, StdSpan>>, StdVector>, strong::type<std::span<const std::string>, VectorViewTag_, StdSpan>>' requested here
include/strong_type/type.hpp:66:21: note: in instantiation of template class 'strong::implicitly_convertible_to<strong::type<std::span<const std::string>, VectorViewTag_, StdSpan>>::modifier<strong::type<std::vector<std::string>, VectorTypeTag_, strong::implicitly_convertible_to<strong::type<std::span<const std::string>, VectorViewTag_, StdSpan>>, StdVector>>' requested here
66 | class type : public modifier<M, type<T, Tag, M...>> ... {
| ^
source.cpp:29:24: note: in instantiation of template class 'strong::type<std::vector<std::string>, VectorTypeTag_, strong::implicitly_convertible_to<strong::type<std::span<const std::string>, VectorViewTag_, StdSpan>>, StdVector>' requested here
29 | [[nodiscard]] VectorType make_vector( Parameters &&...parameters )
| ^
include/strong_type/range.hpp:139:11: note: template is declared here
139 | class modifier;
Compiler: Clang 19.1.7, C++20.
Metadata
Metadata
Assignees
Labels
No labels