简体   繁体   中英

c++ Output stream not working with templates and namespaces

I have the following code:

#include <fstream>

// Removing this namespace (keeping the content) makes it work
namespace baz {

class Bar {
};

}

std::ostream & operator<<(std::ostream & stream, baz::Bar & value) {
  return stream;
}

// Removing this namespace (keeping the content) makes it work
namespace goo {

template <class Type>
struct Point {
};

// Removing this function makes it work
template <class Type>
std::ostream& operator<< (std::ostream& stream, const Point<Type> &point);

void foo() {
  baz::Bar test;
  std::ofstream stream;
  stream << test;
}

}

It does not compile on MSVC and fails with the following error message:

error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'baz::Bar' (or there is no acceptable conversion)

However, if I remove any of the two namespaces (keeping all the contents) or remove the templated << function for the Point class, everything works fine.

Is this a bug in MSVC? How can I make it compile without removing the namespaces or the function?

This is a bug in your code. The overload set for functions is build in multiple stages:

  1. From the current scope outwards find a matching function name. When a name is found in a namespace add all overloads defined in this namespace to the overload set and stop this process.
  2. Add all overloads found by argument dependent look-up (ADL) to the overload set.
  3. Determine if the overload set contains a unique matching and best overload. If so, use that otherwise fail.

Your problem is that your operator<<(std::ostream&, baz::Bar&) is defined in the global namespace rather than in the namespace where Bar is defined (in this case baz ). Putting the overload into namespace baz is needed anyway when using the operator from a template with a name depending on a template argument: in that case the first stage is omitted and only names found by argument dependent look-up are detected.

BTW, while fixing the location of the output operator you might want to consider passing the argument as baz::Bar const& as output operators normally don't modify the formatted entity.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM