In an effort to contribute back to the great matplotlib-cpp library I came across the need of having to create a mechanism that can select between different types in C++. This was needed in order to allow passing data from C++ to python without any copies using the numpy library. The only caveat in this case in that numpy requires to know the type you are passing. Since the matplotlib-cpp library is template-based there is a nice compile-time way to do it using template specialization. In simple terms it boils down to creating a base case for all the types you do not support and specialize for the types you care. Using a simple struct to hold the type completes the whole construct. The final result is :
// Type selector for numpy array conversion
template <typename T>
struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default
template <>
struct select_npy_type<double> { const static NPY_TYPES type = NPY_DOUBLE; };
template <>
struct select_npy_type<float> { const static NPY_TYPES type = NPY_FLOAT; };
template <>
struct select_npy_type<bool> { const static NPY_TYPES type = NPY_BOOL; };
template <>
struct select_npy_type<std::int8_t> { const static NPY_TYPES type = NPY_INT8; };
template <>
struct select_npy_type<std::int16_t> { const static NPY_TYPES type = NPY_SHORT; };
template <>
struct select_npy_type<std::int32_t> { const static NPY_TYPES type = NPY_INT; };
template <>
struct select_npy_type<std::int64_t> { const static NPY_TYPES type = NPY_INT64; };
template <>
struct select_npy_type<std::uint8_t> { const static NPY_TYPES type = NPY_UINT8; };
template <>
struct select_npy_type<std::uint16_t> { const static NPY_TYPES type = NPY_USHORT; };
template <>
struct select_npy_type<std::uint32_t> { const static NPY_TYPES type = NPY_ULONG; };
template <>
struct select_npy_type<std::uint64_t> { const static NPY_TYPES type = NPY_UINT64; };
It can be used as follows :
template<typename Numeric>
PyObject* get_array(const std::vector<Numeric>& v)
{
detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work
NPY_TYPES type = select_npy_type<Numeric>::type;
if (type == NPY_NOTYPE)
{
std::vector<double> vd(v.size());
npy_intp vsize = v.size();
std::copy(v.begin(),v.end(),vd.begin());
PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data()));
return varray;
}
npy_intp vsize = v.size();
PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data()));
return varray;
}