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

std::enable_if fails to act when the wrong type (double) is passed to it instead of std::complex

I would like to have my array class copy data from

double
arrays to
std::complex<double>
(or any U to std::complex) arrays with
operator=
. For that, I used
std::enable_if
. It's, however, failing to detect that it should not be used.

The following function, I want to be called if type
T
is anything complex. So I used the condition
std::is_same<T, std::complex<typename T::value_type>
, because
std::complex
stores the type it uses in
::value_type
. Here's the definition of the function:

template <typename T, int S>
typename std::enable_if<std::is_same<T, std::complex<typename T::value_type> >::value, MyArray<T,S>& >::type
MyArray<T,S>::operator=(const typename std::enable_if<std::is_scalar<typename T::value_type>::value, MyArray<typename T::value_type>&, S >::type rhs)


This, however, gives the following error if I tried to copy
MyArray<double>
. So apparently it's failing to detect that double is not `


error: 'double' is not a class, struct, or union type
MyArray::operator=(const typename std::enable_if::value, MyArray&, S >::type rhs)


What am I doing wrong here?




UPDATE:

I want to make what I want to acheive clear, because (sorry) there's so much confusion.

I need this operation to be possible:

MyArray<double> d;
MyArray<std::complex<double>> cd;
cd = d;

Answer

Not sure to understand but... if you want enable your operator=() only when the incoming MyArray<T> is with T that is a std::complex<U>, why don't you simply write

   template <typename F>
     MyArray & operator= (MyArray<std::complex<F>> const & rhs)
      { return *this }

--EDIT--

I want to assign U to std::complex<U>, so MyArray<std::complex<U>> = MyArray<U>.

So you want the exactly opposite.

I suppose you can do something like

#include <complex>
#include <type_traits>

template <typename T>
struct MyArray
 {
   template <typename U>
   typename std::enable_if<std::is_same<T, std::complex<U>>::value,
         MyArray &>::type 
      operator= (MyArray<U> const & rhs)
       { return *this; }
 };

int main()
 {
   MyArray<double> d;
   MyArray<std::complex<double>> cd;
   cd = d;
 }

-- EDIT 2 --

but there's a second template parameter that I removed in the original question, thinking that I'm simplifying the issue for readability. But it was wrong of me to do that, because partial specializations of functions are not allowed in C++. So my template is template , not template , which is very different

I don't think it's neccessary partial specialization

#include <complex>
#include <type_traits>

template <typename T, int S>
struct MyArray
 {
   template <typename U>
   typename std::enable_if<std::is_same<T, std::complex<U>>::value,
        MyArray &>::type 
    operator= (MyArray<U, S> const & rhs)
     { return *this; }
 };

int main()
 {
   MyArray<double, 3> d;
   MyArray<std::complex<double>, 3> cd;
   cd = d;
 }

If the problem is in defining the operator() outside the body of the class, I propose the following, modified example

#include <complex>
#include <type_traits>

template <typename T, int S>
struct MyArray
 {
   template <typename U>
   typename std::enable_if<std::is_same<T, std::complex<U>>::value,
        MyArray &>::type 
    operator= (MyArray<U, S> const & rhs);
 };

template <typename T, int S>
template <typename U>
typename std::enable_if<std::is_same<T, std::complex<U>>::value,
      MyArray<T, S> &>::type 
   MyArray<T, S>::operator= (MyArray<U, S> const & rhs)
      { return *this; }

int main()
 {
   MyArray<double, 3> d;
   MyArray<std::complex<double>, 3> cd;
   cd = d;
 }