名称空间和使用stl算法的用户定义操作符



当我试图通过std::copy输出元素时,我面临着不可理解的行为。下面的代码正在编译并且工作正常。

namespace Foo {
  enum class Colors { green, red, blue };
  template <typename T>
  std::ostream &operator << (std::ostream &_os, const T &_t) {
      _os << typename std::underlying_type<T>::type(_t);
      return _os;
  }
}
int main() {
  Foo::Colors colors[] = {Foo::Colors::red, Foo::Colors::red, Foo::Colors::blue};
  for( auto c: colors ) { std::cout << c <<std::endl; }
  std::copy(colors, colors + 4, std::ostream_iterator<Foo::Colors>(std::cout, " "));
}

但是,如果我将operator <<移出Foo范围,std::copy就会出现问题。

namespace Foo {
  enum class Colors { green, red, blue };
}
template <typename T>
std::ostream &operator << (std::ostream &_os, const T &_t) {
  _os << typename std::underlying_type<T>::type(_t);
  return _os;
}
int main() {
  Foo::Colors colors[] = {Foo::Colors::red, Foo::Colors::red, Foo::Colors::blue};
  for( auto c: colors) { std::cout << c <<std::endl; } // works fine
  // arising compiler error
  std::copy(colors, colors + 4, std::ostream_iterator<Foo::Colors>(std::cout, " ")); 
  // do not help, too
  {
    using namespace Foo;
    std::copy(colors, colors + 4, std::ostream_iterator<Colors>(std::cout, " ")); 
  }
}

这种行为的原因是什么,正确的解决方法是什么?

您的模板接受所有内容,并将导致歧义:

一个较小的测试用例:

#include <iostream>
// error: ambiguous overload for ‘operator<<’ in ‘std::cout << '12'’
template <typename T>
std::ostream &operator << (std::ostream &_os, const T &_t) {
  _os << typename std::underlying_type<T>::type(_t);
  return _os;
}
int main() {
    std::cout << 'n';
}

只有一个且只有一个(!)操作符<<由于ADL(参数依赖查找)

原因是std::ostream_iterator<Foo::Colors>在名称空间std中搜索operator<<。通常的非限定查找将只在最近的包含该名称的函数的封闭类或命名空间中查找函数。例如:

void meow(int);
namespace foo
{
    void meow(double);
    void find_kitten()
    {
        meow(42); // calls `foo::meow(double)`
    }
}

operator<<也是如此。在命名空间std中,此操作符重载,因此,非限定名称查找停止,并且不搜索全局命名空间。

但是,操作符总是发生与参数相关的查找。如果函数模板位于参数类型之一的关联命名空间中,它将找到它。在第一个示例中是这样,但在第二个示例中不是这样。


侧备注:

函数模板缺少返回值

std::ostream &operator << (std::ostream &_os, const T &_t) {
  _os << typename std::underlying_type<T>::type(_t);
  return _os; // <--- missing
}

相关内容

  • 没有找到相关文章

最新更新