Объявление друга шаблона C для известного имени класса, вложенного в любой другой

#c #templates #inner-classes #friend

#c #шаблоны #внутренние классы #друг

Вопрос:

Добрый вечер.

У меня следующая проблема при написании некоторого общего кода (по крайней мере, на C 11):

Рассмотрим класс с именем I , который может быть вложен в различные классы A, B, …, N:

 class A
{
protected:
  friend class I;
  class I
  {
  } i;
};

class B
{
protected:
  friend class I;
  class I
  {
  } i;
};

etc.
  

На самом деле I это своего рода инструмент интерфейса, автоматически вставляемый в различные пользовательские классы A … N. Не заботьтесь о причине для этого…

Затем существует определенный класс Z, и цель состоит в том, чтобы объявить any I другом Z, чтобы любой I и ничто другое не могло использовать Z, в какой бы класс A … N (определенный позже) он I не был вложен.

Если я объявлю этот способ:

 class Z
{
  friend class A;   // <--- but I don't want to have to know this one
  friend class I;
private:            // creation and use of Z are restricted to tools like I
  Z();
  // other methods
};
  

Тогда это работает только для A::I :

Из A::I::some_function() можно создать и использовать Z, но не из B::I ни какого другого в B … N.

Без friend class A; ни один из I не сможет получить доступ к Z.

  • Как сделать его универсальным?

Я ищу способ написать объявление друга шаблона, предоставляющее доступ для любого, X::I где X — параметр шаблона.

И не является параметром шаблона для, I конечно, поскольку I это не шаблон.

Конечно, я не хочу предоставлять доступ к какому-либо классу X, чтобы любой X::I тоже мог получить доступ к Z !

Следующее не работает:

 class Z
{
  template< class X>  friend class X::I;
  ...
};
  

=> ошибка: ‘I’ не является членом ‘X’

из gcc версии 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.11)

Есть представление о правильном синтаксисе? Я не нашел этого варианта использования в ссылке…

Большое спасибо, с уважением.

================= добавлено 16 августа : Уточнения:

I Существует постоянно как часть A (или другого), в то время как Z это инструмент, работающий только во время определенной операции I , которая может повторяться, затем создается новый Z , используется, а затем удаляется каждый раз как локальный метод I .

Также Z имеет соответствующую полезную нагрузку, и я не хочу делать это постоянной частью каждого объекта, внедряющего I . Например, путем создания Z унаследованного от I .

Комментарии:

1. Итак, если я правильно понимаю, любой класс, имеющий вложенный I тип, должен дружить с Z ? Без ручного указания этих классов в Z вам потребовалось бы отражение, что в настоящее время в c невыполнимо.

2. Я выделил ‘I’ жирным шрифтом, чтобы они были более заметны. @cigien: Нет, только ‘I’ внутри любого ‘X’ должен обращаться к ‘Z’, а не к самому ‘X’. Я просто хочу объявить ‘I’ другом ‘Z’ через любой внешний класс. Изначально я ожидал, что это будет работать только с именем ‘I’, но, видимо, это не так, я получаю ошибку «Z () является частным»

3. Просто короткий комментарий к вашему описанию: «Рассмотрим класс с именем I, который может быть вложен в различные классы A, B, …, N:» — это не описывает его. Существует множество именованных классов I , вложенных в другие классы. Их «полное» имя A::I , B::I и т.д.

4. @Ulrich Eckhardt : Да, это автоматически вставляемый (короткий) код, объявляющий класс, который всегда именуется I внутри пользовательского класса, I будучи идентичным по своей структуре (не обязательно в реализации его методов) для всех таких пользовательских классов, тогда мы могли бы вызвать его *::I в настоящем контексте. Верно, что из-за пути это не тот же тип C , несмотря на то, что это тот же идентификатор (терминала). Вот почему я ожидаю решить проблему с объявлением друга шаблона, позволяющим изменять путь.

Ответ №1:

Вероятно, вы можете достичь того, что пытаетесь сделать, сделав I inherit Z и создав Z абстрактный базовый класс (чтобы к нему нельзя было получить прямой доступ).

Что-то похожее на:

 class Z
{
    virtual void __() = 0;
  public:
    virtual ~Z() = default;
    void method() { std::cout << "Method from Z" << std::endl; }
};

class A
{
    friend class I;
  
  public:
    class I : public Z
    {
        void __() final {}
      public:
        static Z *make_z();
    } i;
};

Z *A::I::make_z()
{
    return new I();
}

int main()
{
    Z *z = A::I::make_z();
    z->method();
    
    return 0;
}
  

Комментарии:

1. Спасибо за идею, но это вызвало бы ужасные проблемы с точки зрения срока службы. Проблема, которую я опубликовал, очень упрощена. На самом деле I существует постоянно как часть A (или другого), в то время как Z это инструмент, работающий только во время определенной операции I , которая может повторяться, затем создается новый Z , используется, а затем удаляется каждый раз как локальный метод I . Также Z имеет соответствующую полезную нагрузку, и я не хочу делать это постоянной частью каждого объекта, внедряющего I . Извините, я не могу сообщить подробности в комментарии, и мне не разрешено публиковать четко отформатированный ответ самому себе.