我碰到了什么对我来说看起来像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
都通过它们的friend
声明被注入命名空间test
,所以它们都不应该出现在全局名称空间中。
Q1是我错了,或者这是C++ 11的新的转折,或者是gcc行为异常?
当然,如果我只是使用指令注入全局命名空间,问题就可以避免。但是,如果我做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有什么不对?
任何子问题的答案欢迎。
“应该看起来像”有点太强大了,因为“使用”可能不是OP真正想要的 - 在某些情况下,您确实希望ADL发生,理解它是什么以及它是如何工作是很重要的。 – 2013-02-28 17:30:37
@DanielFrey:我将“should”改为“will”。 – 2013-02-28 17:32:40
另外,您对Q2的回答有点奇怪,因为编译器总是*解析代码。无论如何,你的回答很有帮助,因此:+1 – 2013-02-28 17:33:06