When a function takes a std::span
of const T
, it cannot deduce the span type from a mutable span that is being passed in.
Is it however possible for a user-defined type to allow the deductionn of the const alternative from the mutable alternative (maybe through the help of deduction guides)?
template<typename T>
struct MySpan
{};
template<typename T>
void takingConst(std::span<const T>)
{}
template<typename T>
void takingMyConst(MySpan<const T>)
{}
int square(int num)
{
std::span<int> stdSpan{};
takingConst(std::span<const int>(stdSpan));
MySpan<int> mySpan{};
takingMyConst(mySpan); //Any way to make this work?
}
Make the non-const
MySpan<T>
inherit from MySpan<const T>
.
Here's a way that is easy to understand:
template<typename T>
struct MySpan : public MySpan<const T> {
MySpan() = default;
MySpan(T* ptr, std::size_t size) : MySpan<const T>(ptr, size) {}
T* data() const { return const_cast<T*>(MySpan<const T>::data()); }
T& operator[](std::size_t i) const { return data()[i]; }
using MySpan<const T>::size;
};
template<typename T>
struct MySpan<const T> {
MySpan() = default;
MySpan(const T* ptr, std::size_t size) : ptr(ptr), sz(size) {}
const T* data() const { return ptr; }
const T& operator[](std::size_t i) const { return data()[i]; }
std::size_t size() const { return sz; }
private:
const T* ptr = nullptr;
std::size_t sz = 0;
};
Here's a way that doesn't duplicate code:
template<typename T>
struct MySpan;
namespace detail {
template<typename T>
struct my_span_members {
private:
T* ptr = nullptr;
std::size_t sz = 0;
template<typename>
friend struct ::MySpan;
};
}
template<typename T>
struct MySpan : std::conditional_t<std::is_const_v<T>, detail::my_span_members<T>, MySpan<const T>> {
private:
using base = std::conditional_t<std::is_const_v<T>, detail::my_span_members<T>, MySpan<const T>>;
public:
MySpan() = default;
MySpan(T* ptr, std::size_t size) : base{ static_cast<const T*>(ptr), size } {}
template<std::size_t N>
MySpan(std::type_identity_t<T>(& arr)[N]) : MySpan(arr, N) {}
// ...
T* data() const { return const_cast<T*>(base::ptr); }
std::size_t size() const { return base::sz; }
T& operator[](std::size_t i) const { return data()[i]; }
// ...
};