Merge topic 'variant-get-unsupported-type'

e9da34310 Handle `Variant::Get` for types not supported by the `Variant`

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2596
This commit is contained in:
Kenneth Moreland 2021-10-08 12:31:09 +00:00 committed by Kitware Robot
commit b4bb02830a
2 changed files with 56 additions and 4 deletions

@ -230,6 +230,11 @@ void TestIndexing()
VTKM_STATIC_ASSERT((std::is_same<VariantType::TypeAt<27>, TypePlaceholder<27>>::value));
VTKM_STATIC_ASSERT((std::is_same<VariantType::TypeAt<28>, TypePlaceholder<28>>::value));
VTKM_STATIC_ASSERT((std::is_same<VariantType::TypeAt<29>, TypePlaceholder<29>>::value));
VTKM_TEST_ASSERT(VariantType::CanStore<TypePlaceholder<2>>::value);
VTKM_TEST_ASSERT(!VariantType::CanStore<TypePlaceholder<100>>::value);
VTKM_TEST_ASSERT(variant.GetCanStore<TypePlaceholder<3>>());
VTKM_TEST_ASSERT(!variant.GetCanStore<TypePlaceholder<101>>());
}
void TestTriviallyCopyable()
@ -352,6 +357,9 @@ void TestGet()
VTKM_TEST_ASSERT(variant.Get<2>() == expectedValue);
VTKM_TEST_ASSERT(variant.Get<vtkm::Id>() == expectedValue);
// This line should compile, but will assert if you actually try to run it.
//variant.Get<TypePlaceholder<100>>();
}
{

@ -305,6 +305,22 @@ public:
template <vtkm::IdComponent Index>
using TypeAt = typename vtkm::ListAt<vtkm::List<Ts...>, Index>;
/// \brief Type that indicates whether another type can be stored in this Variant.
///
/// If this templated type resolves to `std::true_type`, then the provided `T` can be
/// represented in this `Variant`. Otherwise, the type resolves to `std::false_type`.
///
template <typename T>
using CanStore = std::integral_constant<bool, (IndexOf<T>::value >= 0)>;
/// Returns whether the given type can be respresented in this Variant.
///
template <typename T>
VTK_M_DEVICE static constexpr bool GetCanStore()
{
return CanStore<T>::value;
}
/// The number of types representable by this Variant.
///
static constexpr vtkm::IdComponent NumberOfTypes = vtkm::IdComponent{ sizeof...(Ts) };
@ -434,18 +450,46 @@ public:
template <typename T>
VTK_M_DEVICE T& Get() noexcept
{
VTKM_ASSERT(this->GetIndexOf<T>() == this->GetIndex());
return detail::VariantUnionGet<IndexOf<T>::value>(this->Storage);
return this->GetImpl<T>(CanStore<T>{});
}
template <typename T>
VTK_M_DEVICE const T& Get() const noexcept
{
VTKM_ASSERT(this->GetIndexOf<T>() == this->GetIndex());
return detail::VariantUnionGet<IndexOf<T>::value>(this->Storage);
return this->GetImpl<T>(CanStore<T>{});
}
//@}
private:
template <typename T>
VTK_M_DEVICE T& GetImpl(std::true_type)
{
VTKM_ASSERT(this->GetIndexOf<T>() == this->GetIndex());
return detail::VariantUnionGet<IndexOf<T>::value>(this->Storage);
}
template <typename T>
VTK_M_DEVICE const T& GetImpl(std::true_type) const
{
VTKM_ASSERT(this->GetIndexOf<T>() == this->GetIndex());
return detail::VariantUnionGet<IndexOf<T>::value>(this->Storage);
}
// This function overload only gets created if you attempt to pull a type from a
// variant that does not exist. Perhaps this should be a compile error, but there
// are cases where you might create templated code that has a path that could call
// this but never does. To make this case easier, do a runtime error (when asserts
// are active) instead.
template <typename T>
VTK_M_DEVICE T& GetImpl(std::false_type) const
{
VTKM_ASSERT(false &&
"Attempted to get a type from a variant that the variant does not contain.");
// This will cause some _really_ nasty issues if you actually try to use the returned type.
return *reinterpret_cast<T*>(0);
}
public:
//@{
/// Given a functor object, calls the functor with the contained object cast to the appropriate
/// type. If extra \c args are given, then those are also passed to the functor after the cast