//============================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//============================================================================
// **** DO NOT EDIT THIS FILE!!! ****
// This file is automatically generated by VariantDetail.h.in

#if !defined(VTK_M_DEVICE) || !defined(VTK_M_NAMESPACE)
#error VarianImplDetail.h must be included from VariantImpl.h
// Some defines to make my IDE happy.
#define VTK_M_DEVICE
#define VTK_M_NAMESPACE tmp
#endif

#include <vtkm/Types.h>

#include <vtkm/internal/brigand.hpp>

#include <type_traits>



namespace vtkm
{
namespace VTK_M_NAMESPACE
{
namespace internal
{
namespace detail
{

template <typename ReturnType>
struct VariantDummyReturn
{
  VTK_M_DEVICE static inline ReturnType F() noexcept { return ReturnType{}; }
};
template <>
struct VariantDummyReturn<void>
{
  VTK_M_DEVICE static inline void F() noexcept {}
};

template <typename ReturnType, typename Functor, typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(brigand::list<>,
                                                      vtkm::IdComponent,
                                                      Functor&&,
                                                      const void*,
                                                      Args&&...) noexcept
{
  // If we are here, it means we failed to find the appropriate type in a variant
  VTKM_ASSERT(false && "Internal error, bad Variant state.");
  return VariantDummyReturn<ReturnType>::F();
}

// clang-format off

template <typename ReturnType,
          typename T0,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<const T10*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<T10*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<const T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<const T11*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<T11*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<const T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<const T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<const T12*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<T12*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<const T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<const T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<const T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<const T13*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<T13*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<const T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<const T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<const T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<const T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<const T14*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<T14*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<const T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<const T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<const T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<const T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<const T14*>(storage), std::forward<Args>(args)...);
    case 15:
      return f(*reinterpret_cast<const T15*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<T14*>(storage), std::forward<Args>(args)...);
    case 15:
      return f(*reinterpret_cast<T15*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename T16,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<const T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<const T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<const T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<const T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<const T14*>(storage), std::forward<Args>(args)...);
    case 15:
      return f(*reinterpret_cast<const T15*>(storage), std::forward<Args>(args)...);
    case 16:
      return f(*reinterpret_cast<const T16*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename T16,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<T14*>(storage), std::forward<Args>(args)...);
    case 15:
      return f(*reinterpret_cast<T15*>(storage), std::forward<Args>(args)...);
    case 16:
      return f(*reinterpret_cast<T16*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename T16,
          typename T17,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<const T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<const T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<const T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<const T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<const T14*>(storage), std::forward<Args>(args)...);
    case 15:
      return f(*reinterpret_cast<const T15*>(storage), std::forward<Args>(args)...);
    case 16:
      return f(*reinterpret_cast<const T16*>(storage), std::forward<Args>(args)...);
    case 17:
      return f(*reinterpret_cast<const T17*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename T16,
          typename T17,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<T14*>(storage), std::forward<Args>(args)...);
    case 15:
      return f(*reinterpret_cast<T15*>(storage), std::forward<Args>(args)...);
    case 16:
      return f(*reinterpret_cast<T16*>(storage), std::forward<Args>(args)...);
    case 17:
      return f(*reinterpret_cast<T17*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename T16,
          typename T17,
          typename T18,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<const T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<const T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<const T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<const T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<const T14*>(storage), std::forward<Args>(args)...);
    case 15:
      return f(*reinterpret_cast<const T15*>(storage), std::forward<Args>(args)...);
    case 16:
      return f(*reinterpret_cast<const T16*>(storage), std::forward<Args>(args)...);
    case 17:
      return f(*reinterpret_cast<const T17*>(storage), std::forward<Args>(args)...);
    case 18:
      return f(*reinterpret_cast<const T18*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename T16,
          typename T17,
          typename T18,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<T14*>(storage), std::forward<Args>(args)...);
    case 15:
      return f(*reinterpret_cast<T15*>(storage), std::forward<Args>(args)...);
    case 16:
      return f(*reinterpret_cast<T16*>(storage), std::forward<Args>(args)...);
    case 17:
      return f(*reinterpret_cast<T17*>(storage), std::forward<Args>(args)...);
    case 18:
      return f(*reinterpret_cast<T18*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename T16,
          typename T17,
          typename T18,
          typename T19,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<const T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<const T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<const T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<const T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<const T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<const T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<const T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<const T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<const T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<const T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<const T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<const T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<const T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<const T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<const T14*>(storage), std::forward<Args>(args)...);
    case 15:
      return f(*reinterpret_cast<const T15*>(storage), std::forward<Args>(args)...);
    case 16:
      return f(*reinterpret_cast<const T16*>(storage), std::forward<Args>(args)...);
    case 17:
      return f(*reinterpret_cast<const T17*>(storage), std::forward<Args>(args)...);
    case 18:
      return f(*reinterpret_cast<const T18*>(storage), std::forward<Args>(args)...);
    case 19:
      return f(*reinterpret_cast<const T19*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename T16,
          typename T17,
          typename T18,
          typename T19,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  switch (index)
  {
    case 0:
      return f(*reinterpret_cast<T0*>(storage), std::forward<Args>(args)...);
    case 1:
      return f(*reinterpret_cast<T1*>(storage), std::forward<Args>(args)...);
    case 2:
      return f(*reinterpret_cast<T2*>(storage), std::forward<Args>(args)...);
    case 3:
      return f(*reinterpret_cast<T3*>(storage), std::forward<Args>(args)...);
    case 4:
      return f(*reinterpret_cast<T4*>(storage), std::forward<Args>(args)...);
    case 5:
      return f(*reinterpret_cast<T5*>(storage), std::forward<Args>(args)...);
    case 6:
      return f(*reinterpret_cast<T6*>(storage), std::forward<Args>(args)...);
    case 7:
      return f(*reinterpret_cast<T7*>(storage), std::forward<Args>(args)...);
    case 8:
      return f(*reinterpret_cast<T8*>(storage), std::forward<Args>(args)...);
    case 9:
      return f(*reinterpret_cast<T9*>(storage), std::forward<Args>(args)...);
    case 10:
      return f(*reinterpret_cast<T10*>(storage), std::forward<Args>(args)...);
    case 11:
      return f(*reinterpret_cast<T11*>(storage), std::forward<Args>(args)...);
    case 12:
      return f(*reinterpret_cast<T12*>(storage), std::forward<Args>(args)...);
    case 13:
      return f(*reinterpret_cast<T13*>(storage), std::forward<Args>(args)...);
    case 14:
      return f(*reinterpret_cast<T14*>(storage), std::forward<Args>(args)...);
    case 15:
      return f(*reinterpret_cast<T15*>(storage), std::forward<Args>(args)...);
    case 16:
      return f(*reinterpret_cast<T16*>(storage), std::forward<Args>(args)...);
    case 17:
      return f(*reinterpret_cast<T17*>(storage), std::forward<Args>(args)...);
    case 18:
      return f(*reinterpret_cast<T18*>(storage), std::forward<Args>(args)...);
    case 19:
      return f(*reinterpret_cast<T19*>(storage), std::forward<Args>(args)...);
    default:
      // If we are here, it means we failed to find the appropriate type in a variant
      VTKM_ASSERT(false && "Internal error, bad Variant state.");
      return VariantDummyReturn<ReturnType>::F();
  }
}

//clang-format on

// Recurse for cases where Variant has more than 20 types
template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename T16,
          typename T17,
          typename T18,
          typename T19,
          typename T20,
          typename... RemainingT,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, RemainingT...>,
  vtkm::IdComponent index,
  Functor&& f,
  const void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  if (index < 20)
  {
    return VariantCastAndCallImpl<ReturnType>(
      brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>{},
      index,
      f,
      storage,
      args...);
  }
  else
  {
    return VariantCastAndCallImpl<ReturnType>(
      brigand::list<T20, RemainingT...>{}, index - 20, f, storage, args...);
  }
}

template <typename ReturnType,
          typename T0,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5,
          typename T6,
          typename T7,
          typename T8,
          typename T9,
          typename T10,
          typename T11,
          typename T12,
          typename T13,
          typename T14,
          typename T15,
          typename T16,
          typename T17,
          typename T18,
          typename T19,
          typename T20,
          typename... RemainingT,
          typename Functor,
          typename... Args>
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
  brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, RemainingT...>,
  vtkm::IdComponent index,
  Functor&& f,
  void* storage,
  Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
  if (index < 20)
  {
    return VariantCastAndCallImpl<ReturnType>(
      brigand::list<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>{},
      index,
      f,
      storage,
      args...);
  }
  else
  {
    return VariantCastAndCallImpl<ReturnType>(
      brigand::list<T20, RemainingT...>{}, index - 20, f, storage, args...);
  }
}

}
}
}
} // vtkm::VTK_M_NAMESPACE::internal::detail
