С чем связано ограничение на объявление friend функций в локальных классах?

97
07 августа 2019, 14:40

С чем связано ограничение на объявление friend функций в локальных классах?

class A {
    friend void foo(){}; // OK
};

int main() {
    class B {
        friend void foo(){}; // ERROR
    };
}
Answer 1

Объявлять дружественные функции к локальном классе вам никто не запрещает. В вашем примере срабатывает не ограничение на объявление дружественных функций как таковое, а ограничение на определение дружественных функций прямо внутри определения локального класса.

Можно сказать что ситуация проистекает из особенностей использования неквалифицированного имени во friend-объявлениях в локальных классах. Квалифицированные имена во friend-объявлениях использовать можно обычным образом (т.е., как всегда с квалифицированными именами, такие friend-объявления должны ссылаться на уже известные функции)

void foo() {}
int main()
{
  class A {
    friend void foo(); // <- Так нельзя
  };
  class B {
    friend void ::foo(); // <- А так можно
  };
}

Особенность же неквалифицированного имени заключается в том, что по правилам friend-объявлений, такое объявление ссылается на сущность в ближайшей охватывающей не-класс области видимости. В вышеприведенном примере friend-объявление в классе A ссылается на имя функции foo, локальное в main.

Такая трактовка неквалифицированного имени необходима потому, что это - единственный способ, при помощи которого локальные классы могут ссылаться друг на друга. По понятным причинам квалифицированных имен у таких классов нет.

Что интересно, "спасти" такое friend-объявление еще можно, если насильно "притащить" в локальную область видимости объявление существующей функции с таким именем

void foo() {}
int main()
{
  void foo(); // Объявление ссылается на `::foo`
  class A {
    friend void foo(); // <- Так можно
    // Ссылается на локальное имя `foo` в main, которое ссылается на `::foo`
  };
}

Но к определениям новых функций (как в вашем примере) эта лазейка не относится - оно бы фактически пыталось определить локальную функцию в main.

Можно заметить: а почему бы не модифицировать спецификацию friend-объявлений и не сказать, что неквалифицированные имена в определениях ссылаются на сущности в ближайшей охватывающей области видимости уровня namespace?

Я не вижу технических ограничений для такой реализации. С тем только замечанием, что это приведет к разной трактовке неквалифицированных имен во friend-объявлениях и во friend-определениях. Что некрасиво.

Актуальность этой темы, кстати, потенциально выросла с C++14, в котором локальные классы стали совсем не такими локальными, какими они были раньше

auto foo() 
{
  struct S 
  {
    void bar() {}
  };
  return S();
}
int main() 
{
  auto a = foo();
  a.bar();
  decltype(a) b;
  b.bar();
}    
Answer 2

Я думаю, что проблема связана с тем, что friend-объявление не вводит объявленную функцию в область объявления. Функция является невидимой. Поэтому не имеет смысла определять friend-функцию в области объявления локального класса.

Когда же такое определение friend-функции встречается в нелокальном объявлении класса, то может подключаться зависящий от аргумента поиск (ADL), который рассматривает ассоциативные пространства имен и таким образом находит объявленную в классе функцию.

READ ALSO
Как сделать , чтобы после нажатия на крестик(закрыть приложение), выскакивал MessageBox?

Как сделать , чтобы после нажатия на крестик(закрыть приложение), выскакивал MessageBox?

Вот про логику, как сделать сам MessageBox , я знаюВпихиваю код в деструктор:

125
Нужно поменять тип линии в JFreeChart

Нужно поменять тип линии в JFreeChart

Здравствуйте появилась проблема с поиском в документации информации :( А именно то, что я не нашел как поменять тип линии, ее цвет и как добавить...

110
Добавить прокси к моему приложению на Android

Добавить прокси к моему приложению на Android

Я хочу узнать как правильно добавить прокси к моему приложениюТак получилось, что сайт, который я парсю попал в реестр РКН, мне нужен способ...

127