The following code (surprisingly?) does not compile with either g++ or clang++ due to ambiguous calls to BuildStream when instantiating bar::BuildStream with bar::Rectangle as an input.
#include <iostream>
#include <sstream>
namespace foo {
struct Rectangle { double height, width; };
std::ostream& operator<<(std::ostream& os, const Rectangle& a) { return os; }
inline void BuildStream(std::ostringstream& os) { }
template<typename T, typename... Args>
void BuildStream
(std::ostringstream& os, const T& item, const Args& ...args) {
os << item;
BuildStream(os, args...);
}
} // namespace foo
namespace bar {
inline void BuildStream(std::ostringstream& os) { }
template<typename T, typename... Args>
void BuildStream
(std::ostringstream& os, const T& item, const Args& ...args) {
os << item;
BuildStream(os, args...);
}
using Rectangle = foo::Rectangle;
} // namespace bar
int main(int argc, char* argv[]) {
std::ostringstream os;
bar::BuildStream(os, 1, 2);
bar::BuildStream(os, bar::Rectangle(), bar::Rectangle());
return 0;
}
The ambiguity would seem to imply that, generally speaking, if a class is imported from namespace foo into namespace bar, then care must be taken to ensure that no functions in bar have names equal to functions in foo. This clearly throws a wrench in some of the benefits of namespaces; is there a more nuanced approach to avoiding such ambiguities?
The context is foo being the namespace of a large library and bar being a consumer project's namespace (and this problem showed up in practice).