Шаблон класу з шаблоном класний друг, що насправді тут відбувається?


80

Скажімо, я створюю клас для двійкового дерева, BTі у мене є клас, який описує елемент дерева BE, щось на зразок

template<class T> class BE {
    T *data;
    BE *l, *r;
public:
...
    template<class U> friend class BT;
};

template<class T> class BT {
    BE<T> *root;
public:
...
private:
...
};

Здається, це працює; однак у мене є питання про те, що відбувається знизу.

Спочатку я намагався оголосити друга таким

template<class T> friend class BT;

однак видається необхідним використовувати U(або щось інше, ніж T) тут, чому це? Чи означає це, що якийсь особа BTє другом для якогось конкретного BEкласу?

Сторінка IBM на шаблонах та друзях містить приклади різних типів взаємозв’язків з друзями для функцій, але не класів (і вгадування синтаксису ще не сходилось у рішенні). Я хотів би зрозуміти, як правильно визначити специфікації для типу стосунків з друзями, який я хочу визначити.

Відповіді:


111
template<class T> class BE{
  template<class T> friend class BT;
};

Не дозволяється, оскільки параметри шаблону не можуть затінювати один одного. Вкладені шаблони повинні мати різні імена параметрів шаблону.


template<typename T>
struct foo {
  template<typename U>
  friend class bar;
};

Це означає, що barє другом fooнезалежно від barаргументів шаблону. bar<char>, bar<int>, bar<float>, І будь-який інший barби бути друзями foo<char>.


template<typename T>
struct foo {
  friend class bar<T>;
};

Це означає, що barє другом того, fooколи barаргумент шаблону збігається з аргументом foo. Тільки bar<char>б був другом foo<char>.


У вашому випадку friend class bar<T>;повинно бути достатньо.


2
ця конструкція в моєму коді друг клас BT <T> видає помилку для помилки рядка друга: 'BT' не є шаблоном, хоча він оголошений пізніше як шаблон <клас T> клас BT {...}
Майкл Конлен

2
Отже, секрет полягає в тому, що мені потрібно було переслати BT, щоб використовувати клас друзів BT <T>; рядок у BE, але не для шаблону <клас U> друг класу BT ;. Дякую за допомогу!
Michael Conlen

24
Якщо бути більш конкретним: вам потрібно переслати декларацію template<typename T> class BT; перед визначенням BE, а потім використовувати friend class BT<T>; всередині класу BE.
Бартош Мілевський,

7

Для того, щоб подружитися з іншою однотипною структурою:

#include <iostream>

template<typename T_>
struct Foo
{
    // Without this next line source.value_ later would be inaccessible.
    template<typename> friend struct Foo;

    Foo(T_ value) : value_(value) {}

    template <typename AltT>
    void display(AltT &&source) const
    {
        std::cout << "My value is " << value_ << " and my friend's value is " << source.value_ << ".\n";
    }

protected:
    T_ value_;
};

int main()
{
    Foo<int> foo1(5);
    Foo<std::string> foo2("banana");

    foo1.display(foo2);

    return 0;
}

Вихід наступний:

My value is 5 and my friend's value is banana. 

У template<typename> friend struct Foo;годі було писати Tпісля того, як typename/ в classіншому випадку це призведе до шаблонним параметрам затінення помилки.


3
Будь ласка, вдосконаліть свою відповідь.
swiftBoy

саме те, що я шукав! ;)
джилім

3

Не потрібно називати параметри, щоб ви отримували менше точок відмови при рефакторингу:

     template <typename _KeyT, typename _ValueT> class hash_map_iterator{
       template <typename, typename, int> friend class hash_map;
       ...

-3

У моєму випадку це рішення працює правильно:

template <typename T>
class DerivedClass1 : public BaseClass1 {
  template<class T> friend class DerivedClass2;
private:
 int a;
};

template <typename T>
class DerivedClass2 : public BaseClass1 {
  void method() { this->i;}
};

Сподіваюся, це буде корисно.


6
Як це рішення має працювати коректно, коли ви заслінюєте параметри шаблону і в іншому випадку не використовуєте доступ друга DerivedClass2 до DerivedClass1?
kornman00
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.