We have classes A and B that look like
struct A {
int x;
auto display() const noexcept -> void { /* displaying */ }
};
struct B final : A {
/* no added members */
auto foo() const noexcept -> void { ... }
};
With a function
auto display_all_as(std::span<A const> as) noexcept -> void {
for (auto const a : as)
a.display()
}
We can call this function like
auto constexpr a_arr = std::array<A, 3>{};
display_all_as(a_arr);
but if we try and call it in the following way it doesn't work
auto constexpr b_arr = std::array<B, 3>{};
display_all_as(b_arr); // error: no known conversion from array<B,3> to array<A,3>
I have gotten the code to work by changing the function to
template <class T>
requires std::ranges::range<T> and std::is_convertible_v<typename T::value_type, a>
auto constexpr display_all_as(T as) noexcept -> void {
for (auto const a : as)
a.display();
}
After looking at [[]].
But obviously it requires that the container type implements value_type, which may not be the case if you're using custom containers.
Additionally looking at the assembly output from clang++ main.cpp -std=c++20 -O3 -S
(with clang++ version 19.1.7), it generates two ostensibly identical functions, one specialized to A
and the other specialized to B
.
I'm trying to have the same/ a similar API, but I would like a more optimized and general way, i.e. not having two pieces of assembly being output.
I'm not entirely sure it's possible, I know you can't just convert array<child> -> array<parent>
because it would lead to object splicing issues, but in this case B
doesn't add any members to A
so it seems like we should be able to convert array<B> -> array<A>
.