2

I would like to allow implicit conversion when summing complex numbers. For example:

 complex<double> a; 
 complex<long double> b;
 int i;

 auto sum = a + b; // (1)
 auto SUM = a + i; // (2)

I have the code that enable conversion (1) thanks to answer implicit type promotion in summing two complex<> In order to enable also the (2) conversion I used enable_if_t

  template <typename T, typename U>
  auto operator +(const ::std::complex<T> &a,     std::enable_if_t<std::is_arithmetic<U>::value, U>  &b) 
  {
   typedef decltype(::std::declval<T>() + ::std::declval<U>()) comcomp_t;
   typedef ::std::complex<comcomp_t> result_t;
   return ::std::operator +(result_t{a}, result_t{b});
  }

However, I got a compilation error saying "couldn't deduce template paramter 'U'. I guess my comprehension of SFINAE is very shallow. Any help would be highly appreciated. Thanks

Quentin
  • 62,093
  • 7
  • 131
  • 191
Federico
  • 91
  • 3
  • Please read this " This requires C++14 for the 'auto' (aka deduced) return type. For C++11 you'd basically have to repeat the decltype expression inside the operator for the return type." in one of the answers. – ABcDexter Dec 06 '17 at 17:33
  • I am passing the c++14 flag to the compiler. I edited the tag. Thanks – Federico Dec 06 '17 at 17:35

2 Answers2

1

The second argument is a non-deduced context. You have to rewrite this so that U can actually be deduced. The typical way is to stick the SFINAE into the return type.

 template <typename T, typename U>
 using add_t = decltype(std::declval<T>() + std::declval<U>());

 template <typename T, typename U>
 auto operator+(const std::complex<T>& a, const U& b)
     -> std::enable_if_t<std::is_arithmetic<U>::value,
                         std::complex<add_t<T, U>>>
 {
     std::complex<add_t<T, U>> res = a;
     res += b;
     return res;
 }
Barry
  • 286,269
  • 29
  • 621
  • 977
0

I am not sure that you need SFINAE here. A minimal working C++14 code is:

#include <ccomplex>
#include <type_traits>

template <typename T, typename U>
using add_t = decltype(std::declval<T>() + std::declval<U>());

template <typename T, typename U>
constexpr std::complex<add_t<T, U>> operator+(const std::complex<T>& a,
                                              const std::complex<U>& b) noexcept
{
  using returnType = decltype(a + b);
  return returnType(a.real() + b.real(), a.imag() + b.imag());
}

template <typename T, typename U>
constexpr std::complex<add_t<T, U>> operator+(const std::complex<T>& a,
                                              const U& b) noexcept
{
  using returnType = decltype(a + b);
  return returnType(a.real() + b, a.imag());
}

template <typename T, typename U>
constexpr auto operator+(const T& a, const std::complex<U>& b) noexcept
{
  return b + a;  // assume commutativity of + operator
}

using namespace std;

int main()
{

  constexpr complex<double> a;
  constexpr complex<long double> b;
  constexpr int i = 1;

  constexpr auto s1 = a + b;  // (1)
  constexpr auto s2 = a + i;  // (2)
  constexpr auto s3 = i + a;  // (3)
  constexpr auto s4 = a + 2;  // (4)
  constexpr auto s5 = 2 + a;  // (5)
}

Note: it also works with constexpr expressions.

Picaud Vincent
  • 10,518
  • 5
  • 31
  • 70