Last time, we developed a pattern for cloning a Windows Runtime vector in the face of possible concurrent modification. Let’s try to make a function out of this pattern.
template<typename V>
auto clone_as_vector(V const& v)
-> std::vector<decltype(v.GetAt(0))>
{
using T = decltype(v.GetAt(0));
std::vector<T> temp;
uint32_t expected;
uint32_t actual;
do {
expected = v.Size();
temp.resize(expected + 1, winrt_empty_value<T>());
actual = v.GetMany(0, temp);
} while (actual > expected);
temp.erase(temp.begin() + actual, temp.end());
return temp;
}
template<typename V>
auto CloneVector(V const& v)
-> winrt::Windows::Foundation::
Collections::IVector<decltype(v.GetAt(0))>
{
return winrt::multi_threaded_vector(
clone_as_vector(v));
}
There are some sneaky bits here.
First of all, we make clone_ generic in that all it requires is that the v parameter support GetAt() and GetMany(). This allows the clone_ to work with both IVector and IVectorView.
Second, we use an explicit trailing return type instead of just letting the compiler figure it out from the return statement. This allow SFINAE to remove the function from consideration, allowing us to define other versions of clone_ that work for other collection types.¹
This seems to work, until we run into IVector<bool>, because that cause the clone_ function to create a std::vector<bool>.
Uh-oh.
We’ll try to fix that next time.
¹ Though our trailing return type validates only that GetAt() works. This means that it will accidentally activate for BindableÂVector and BindableÂVectorÂView, which have GetAt() but not GetMany(). I guess we could fix that by adding more junk:
template<typename V>
auto clone_as_vector(V const& v)
-> std::enable_if_t<
std::is_integral_v<decltype(v.GetMany(0, {}))>,
std::vector<decltype(v.GetAt(0))>>
0 comments