2

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; 
10
  • Can you show us all your code? Do you have any other overloads of operator=? Commented Oct 11, 2016 at 16:06
  • This seams overly complex. Doesn't template <typename T> MyArray<T> MyArray<T>::operator=(const std::complex<T>& rhs) do what you want? Commented Oct 11, 2016 at 16:06
  • @kirbyfan64sos The whole code is really, really huge. I'm happy to add any bits you find necessary. Yes there's another operator=, but it's the standard operator= with nothing special. Commented Oct 11, 2016 at 16:08
  • @NathanOliver No, this is the other way around. I want to go from real to complex, not the other way around. Commented Oct 11, 2016 at 16:08
  • So what exactly are you trying to assign to your MyArray? Sorry but I am having a hard time figuring it out. Commented Oct 11, 2016 at 16:09

2 Answers 2

3

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; } 

-- EDIT 3 --

Is there a way to do the same with the copy constructor? [...] It's quite tricky and seems impossible because there's no return type.

Yes, there is a way

#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; } template <typename U, typename = typename std::enable_if<std::is_same<T, std::complex<U>>::value>::type> MyArray (MyArray<U, S> const & rhs) { } MyArray() = default; MyArray(MyArray const &) = default; MyArray(MyArray &&) = default; ~MyArray() = default; }; int main() { MyArray<double, 3> d; // need MyArray() = default MyArray<double, 3> d2(d); // OK MyArray<float, 3> f; // OK MyArray<std::complex<double>, 3> cd(d); // OK //MyArray<std::complex<double>, 3> cd2(f); // error! cd = d; } 

Observe the = default added lines; without the first one (I don't know the other three are usefull or not) the code doesn't compile because (if I understand correctly) the SFINAE copy constructor disable (delete) the default copy constructor so delete the other default constructors and the default destructor.

Sign up to request clarification or add additional context in comments.

10 Comments

See the comment thread under the Q. This is not what the OP wants. I had the same thought and asked.
What I need is the opposite. Please check the update.
@TheQuantumPhysicist - I've seen your comment; modified my answer.
This gives me the error: error: invalid use of incomplete type 'class MyArray<_T, _S>' MyArray<T,S>::operator=(MyArray<U, S>& rhs)
@TheQuantumPhysicist - interesting; modified the example to show the main() (with your example) and includes; it compile with my g++ (4.9.2) and clang++ (3.5); can you show us a minimal example that give the error?
|
1

Something I find helps when trying to understand template problems is try a replacement yourself:

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

Is it obvious now? If double is your MyArray type T, then that T will be used in your SFINAE logic above. But double does not have a ::value_type.

You might try something like this:

template<typename T> typename std::enable_if<std::is_scalar<T>, MyArray<T>&>::type MyArray<T>::operator=(const std::complex<T>& rhs){...} 

And if you don't need the is_scalar check, use max66's answer instead.

Update:
Okey-dokey. So this should address wanting to go from MyArray<T> to MyArray<std::complex<T>> via the assignment operator and not the other way around.

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

The trick here is that int and std::complex<int> are not the same type. You can also do it by substituting T::value_type for U. Finally, you can do it by partially specializing your MyArray<T> class for cases where it's MyArray<std::complex<T>> class, which, if you ever find yourself needing more things like what you were asking, might be worth considering.

4 Comments

What I need is the opposite. Please check the update.
Could you please consider the existence of a second int template parameter? I think this is the source of the problem. Please take a look at the updated code I put in my question.
@TheQuantumPhysicist Your updated code you put in your question shows using double as an example... What do you mean a second int template parameter?
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 <typename T, int S>, not template <typename T>, which is very different.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.