The Quantum Physicist The Quantum Physicist - 1 month ago 7
C++ Question

Template function overload for std::complex

I have a function that generates random number for my array. I created two overloads for floating-point numbers and integers as follows:

template <typename T, int M = 0>
typename std::enable_if<std::is_floating_point<T>::value && std::is_scalar<T>::value,MyArray<T,M> >::type
Random()
{
//...
}

template <typename T, int M = 0>
typename std::enable_if<std::is_integral<T>::value && std::is_scalar<T>::value, MyArray<T,M> >::type
Random()
{
//...
}


These functions can be called with:

MyArray<int> i = Random<int>();
MyArray<double> d = Random<double>();


I would like to achieve the same but with
std::complex<T>
, where
T
can be any floating point type (initially double and float are good enough). I want to be able to do this:

//This is what I'm trying to achieve
MyArray<std::complex<double> > = Random<std::complex<double>>();
MyArray<std::complex<float > > = Random<std::complex<float >>();


I was unable to achieve this exactly, but was able to achieve:

Random<std::complex,double>()


using template template parameters, which is not what I'm looking for.

How can I get the overload with
<std::complex<double>>
(or float) to work?

Answer

I suppose that creating an extractor helper (to, by example, extract float from std::complex<float>) as

template <typename T>
struct extractType;

template <template <typename ...> class C, typename D>
struct extractType<C<D>>
 { using subType = D; };

you can use it and write

template <typename T, int M = 0,
          typename D = typename extractType<T>::subType>
typename std::enable_if<   std::is_same<T, std::complex<D>>::value
                        && std::is_floating_point<D>::value
                        && std::is_scalar<D>::value, MyArray<T,M> >::type
Random ()
 { return MyArray<T,M>{}; }

or simply

template <typename T, int M = 0,
          typename D = typename extractType<T>::subType>
typename std::enable_if<std::is_same<T, std::complex<D>>::value,
                        MyArray<T,M> >::type
Random ()
 { return MyArray<T,M>{}; }

if you can consider obvious that the template argument of std::complex is floating and scalar.

--- EDIT ---

Added a full example (well... with a false MyArray)

#include <array>
#include <complex>
#include <type_traits>

template <typename T, int M = 0>
using MyArray = std::array<T, 10U>;


template <typename T>
struct extractType;

template <template <typename ...> class C, typename D>
struct extractType<C<D>>
 { using subType = D; };


template <typename T, int M = 0>
typename std::enable_if<std::is_floating_point<T>::value && std::is_scalar<T>::value,MyArray<T,M> >::type
Random ()
 { return MyArray<T,M>{}; }

template <typename T, int M = 0>
typename std::enable_if<std::is_integral<T>::value && std::is_scalar<T>::value, MyArray<T,M> >::type
Random ()
 { return MyArray<T,M>{}; }


template <typename T, int M = 0,
          typename D = typename extractType<T>::subType>
typename std::enable_if<std::is_same<T, std::complex<D>>::value,
                        MyArray<T,M> >::type
Random ()
 { return MyArray<T,M>{}; }


int main()
 {
   MyArray<int>                 i = Random<int>();
   MyArray<double>              d = Random<double>();
   MyArray<std::complex<float>> c = Random<std::complex<float>>();
 }
Comments