Proszę spojrzeć na ten fragment kodu. Wiem, że to nie ma sensu, to tylko w celu zilustrowania problemu jestem napotykają:Funkcja szablonu członka klasy A zadeklarowana jako przyjaciel w klasie B nie może uzyskać dostępu do prywatnych członków klasy A (tylko Clang)
#include <iostream>
using namespace std;
struct tBar
{
template <typename T>
void PrintDataAndAddress(const T& thing)
{
cout << thing.mData;
PrintAddress<T>(thing);
}
private:
// friend struct tFoo; // fixes the compilation error
template <typename T>
void PrintAddress(const T& thing)
{
cout << " - " << &thing << endl;
}
};
struct tFoo
{
friend void tBar::PrintDataAndAddress<tFoo>(const tFoo&);
private:
int mData = 42;
};
struct tWidget
{
int mData = 666;
};
int main()
{
tBar bar;
bar.PrintDataAndAddress(tWidget()); // Fine
bar.PrintDataAndAddress(tFoo()); // Compilation error
return 0;
}
Powyższy kod powoduje następujący błąd:
source_file.cpp:10:3: error: 'PrintAddress' is a private member of 'tBar' PrintAddress(thing); source_file.cpp:42:6: note: in instantiation of function template >specialization 'tBar::PrintDataAndAddress' requested here bar.PrintDataAndAddress(tFoo()); // Compilation error source_file.cpp:17:7: note: declared private here void PrintAddress(const T& thing)
ale tylko w Clang ++. GCC i MSVC są w porządku z nim (można szybko sprawdzić, wklejając ten kod w http://rextester.com/l/cpp_online_compiler_clang)
Wydaje się jakby tBar::PrintDataAndAddress<tFoo>(const tFoo&)
wykorzystuje taki sam dostęp jak tFoo
, gdzie jest zaprzyjaźniony. Wiem o tym, ponieważ zaprzyjaźnienie się z tFoo
w rozwiązuje ten problem. Problem również ustępuje, jeśli tBar::PrintDataAndAddress
jest funkcją inną niż szablonowa.
Nie znalazłem w standardzie żadnych informacji wyjaśniających to zachowanie. Wierzę, że może to być zła interpretacja 14.6.5 - temp.inject, ale nie mogę twierdzić, że przeczytałem to wszystko.
Czy ktoś wie, czy Clang ma rację nie skompilować powyższy kod? Czy możesz podać odpowiedni tekst standardowy C++, jeśli tak jest?
Wygląda na to, że aby ten problem mógł się pojawić, dostęp do prywatnego elementu musi być funkcją szablonu. np. w powyższym przykładzie, jeśli stwierdzisz, że PrintAddress jest funkcją inną niż szablon, kod skompiluje się bez błędów.
Może brakuje mi czegoś, ale wydaje mi się całkowicie rozsądne, że klang nie kompiluje tego. Dziwne jest to, że deklaracja przyjaciela skomentowała, powoduje to kompilację. Wydaje mi się, że nie powinno się kompilować, niezależnie. W przeszłości spotkałem się z kilkoma przypadkami, w których gcc ma "zbyt łagodne" błędy w odniesieniu do przyjaźni, w których bierze udział wiele szablonów, tak jest w tym przypadku. –
@NirFriedman dlaczego uważasz, że rozsądne jest, że Clang tego nie kompiluje? Wydaje mi się to sprzeczne z intuicją. klasa A daje znajomemu dostęp do funkcji członkowskiej klasy B (funkcja szablonu w tym przypadku), więc ma dostęp do prywatnych i chronionych członków A, ale dlaczego miałaby ona usunąć dostęp do prywatnych/chronionych członków B? – TheProgammerd
Wygląda mi jak błąd w klangach. Wyszukiwanie, czy jest już zgłoszone. – aschepler