Я столкнулся с тем, что для меня выглядит как несогласованность компилятора 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, используя зЬй = C++ 11) жалуется на «foo
не был объявлен в этой области» (и предлагает в качестве альтернативы test::foo
), но, к счастью компилирует использование от bar
в следующей строке. Теперь оба, foo
и bar
вводятся в пространство имен test
через их объявление friend
, поэтому они не должны действительно присутствовать в глобальном пространстве имен.
Q1 Я ошибаюсь, или это новый поворот C++ 11, или gcc misbehaving?
Конечно, проблему можно избежать, если я просто ввел использование директив в глобальное пространство имен. Тем не менее, если я 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::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;
когда НКУ снова жалуется, на этот раз утверждая, что void test::foo(const test::A<T>&, F)
используется, но не определен ... Так Q3, что случилось?
Ответы на любые приветственные подзадачи.
«Должен выглядеть» - это слишком сильно, потому что «использование» может не быть тем, что действительно хочет OP - в некоторых случаях вы действительно хотите, чтобы ADL произошла, и важно понять, что это такое и как оно работает. –
@ DanielFrey: Я изменил «должен» на «волю». –
Кроме того, вы отвечаете на Q2, немного странно, поскольку компилятор всегда * анализирует * код. Во всяком случае, ваш ответ весьма полезен, поэтому: +1 –