将单个 class 导入命名空间似乎要求命名空间之间没有函数名称冲突

Importing a single class into a namespace appears to require that there be no function name collisions between the namespaces

由于在使用 bar::Rectangle 实例化 bar::BuildStream 时对 BuildStream 的模糊调用,以下代码(令人惊讶?)无法使用 g++clang++ 进行编译] 作为输入。

#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;
}

歧义似乎意味着,一般来说,如果将 class 从命名空间 foo 导入命名空间 bar,则必须注意确保没有函数bar 中的名称等同于 foo 中的函数。这显然破坏了命名空间的一些好处;是否有更微妙的方法来避免这种歧义?

上下文是 foo 是一个大型库的命名空间,bar 是一个消费者项目的命名空间(这个问题在实践中出现了)。

这里的问题与参数相关的查找有关。 bar::Rectangle 实际上是一个 foo::Rectangle,因此对 BuildStream(os,args...) 的调用需要检查 foo's 命名空间以及重载。

确实需要小心。您可以通过限定调用来避免歧义:

  template<typename T, typename... Args>
  void BuildStream(std::ostringstream& os, const T& item, const Args& ...args)
  {
    os << item;
    bar::BuildStream(os, args...); // qualified
  }