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.
operator=?template <typename T> MyArray<T> MyArray<T>::operator=(const std::complex<T>& rhs)do what you want?operator=, but it's the standardoperator=with nothing special.MyArray? Sorry but I am having a hard time figuring it out.