我遇到了在我看来 C++ 编译器的不一致。在以下示例代码中
#include <vector>
namespace test {
  class A : std::vector<int>
  {
    template<typename F>
    friend void bar(A const&a, F f) { for(auto i:a) f(i); }
    template<int K, typename F>
    friend void foo(A const&a, F f) { for(auto i:a) if(i&K) f(i); }
  };
}
int sum(test::A const&a)
{
  int s=0;
  foo<2>(a,[&s](int i) { s+=i; } );    // <-- error here
  bar   (a,[&s](int i) { s+=i; } );    // <-- but not here
  return s;
}
gcc(4.7.0,使用 std=c++11)抱怨“foo未在此范围内声明”(并建议test::foo作为替代方案),但愉快地编译了bar下一行中的用法。现在两者foo都通过它们的声明bar注入到命名空间中,因此它们都不应该真正存在于全局命名空间中。testfriend
Q1我是不是弄错了,或者这是 c++11 的新版本,还是 gcc 行为不端?
当然,如果我只是将 using 指令注入到全局命名空间中,就可以避免这个问题。但是,如果我制作A模板,
#include <vector>
namespace test {
  template<typename T>
  class A : std::vector<T>
  {
    template<typename F>
    friend void bar(A const&a, F f) { for(auto i:a) f(i); }
    template<int K, typename F>
    friend void foo(A const&a, F f) { for(auto i:a) if(i&K) f(i); }
  };
}
using test::foo;          // does not avoid compilation error
using test::bar;          // does not avoid compilation error
int sum(test::A<int> const&a)
{
  int s=0;
  foo<2>(a,[&s](int i) { s+=i; } );
  bar   (a,[&s](int i) { s+=i; } );
  return s;
}
gcc 再次抱怨。要么(没有using指令)“foo未在此范围内声明”(但再次愉快地编译bar,但不建议test::foo)或(使用using指令)“test::foo尚未声明”(与 相同test::bar)在点using指示。
Q2这在我看来像是一个编译器错误,因为无论有无using指令,我都不能调用test::foo. 或者也许我错过了一些关于 C++ 的东西?
最后,我尝试将朋友定义移到班级之外,如
namespace test {
  template<typename T>
  class A : std::vector<int>
  {
    template<int K, typename F>
    friend void foo(A const&a, F f);
    template<typename F>
    friend void bar(A const&a, F f) { for(auto i:a) f(i); }
  };
  template<int K, typename T, typename F>
  void foo(A<T> const&a, F f) { for(auto i:a) if(i&K) f(i); }
}
using test::foo;
当 gcc 再次抱怨时,这一次声称void test::foo(const test::A<T>&, F)已使用但从未定义......所以Q3有什么问题?
欢迎回答任何子问题。