Search code examples
c++template-argument-deduction

Error when using operator << with implicitly converted non-fundamental data types


I have a struct that works as a wrapper for other types as follows:

template<typename T>
struct A {
  A& operator=(const T& value){
    m_value = value;
    return *this;
  }

  operator T() const {
    return m_value;
  }

private:
  T m_value;
};

I use it like this:

int main() {
  A<int> a;
  a = 5;                  // Copy assignment constructor
  std::cout << a << "\n"; // Implicit conversion to int
}

which works as expected. My problem occurs when using non-fundamental types as the following example shows:

int main() {
  A<std::complex<int>> c;
  c = std::complex<int>(2, 2);  
  std::cout << c << "\n";
}

The snippet above raises an invalid operands to binary expression error.

Why does this error occur? Why isn't the overloaded operator << of std::complex<int> used with the implicitly converted A<std::complex<int>>?


Solution

  • The stream operators for std::complex are template functions. They will not be invoked unless you actual have a std::complex as no conversions happens in template argument deduction. This means the compiler will not find a suitable overload to print a A<std::complex<int>>

    You're first case for works because std::basic_ostream::operator << is overloaded to take an int and you are allowed one user defined conversion is overload resolution.


    As a work arround you can define your own operator << that takes your wrapper and forward to the underlying types' operator <<. That would look like

    template<typename T>
    std::ostream& operator <<(std::ostream& os, const A<T>& a)
    {
        return os << static_cast<T>(a);
    }