我碰到了什麼對我來說看起來像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