mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 13:23:51 +00:00
Handle Variant::Get
for types not supported by the Variant
Previously, if you called `Get` on a `Variant` with a type that is not in the list of types supported by the `Variant`, that would attempt to look up the type at index `-1` and could spin the compiler into an endless loop. Instead, check for the case where you are attempting to get a type from the `Variant` not listed in its templat arguments. In this case, instead of producing a compiler error, produce a runtime error. Although this increases the possibility that a bad compile path is being generated, it simplifies creating templated code that produces cases we don't care about.
This commit is contained in:
parent
a607679cb1
commit
e9da343109
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user