Есть ли какое-либо применение для объявлений локальных функций - PullRequest
19 голосов
/ 23 июня 2009

Большинство программистов на C ++, таких как я, в какой-то момент допустили следующую ошибку:

class C { /*...*/ };

int main() {
  C c();     // declares a function c taking no arguments returning a C,
             // not, as intended by most, an object c of type C initialized
             // using the default constructor.
  c.foo();   // compiler complains here.

  //...
}

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

Я думаю, что локальные классы в стиле Java - довольно приятная функция, которую я часто использую, особенно анонимная. Даже локальные классы C ++ (которые могут иметь встроенные функции-члены) имеют некоторое применение. Но это объявление локальной функции без определения мне кажется очень неловким. Это просто C-legacy или есть какой-то более глубокий вариант использования, о котором я не знаю?

Редактировать для неверующих: C c() это , а не объявление указателя функции.

Эта программа

int main()
{
  void g();
  cout << "Hello ";
  g();
  return 0;
}

void g()
{
  cout << "world." << endl;
}

выходы Hello world. Эта программа

void fun()
{
  cout << "world." << endl;
}

int main()
{
  void g();
  g = fun;
  cout << "Hello ";
  g();
  return 0;
}

не компилируется. GCC жалуется:

error: cannot convert 'void ()()' to 'void ()()' in assignment

Комео:

error: expression must be a modifiable lvalue

Ответы [ 7 ]

11 голосов
/ 23 июня 2009

Единственное использование, которое я могу придумать, - это уменьшить объем объявлений функций:

int main()
{
    void doSomething();
    doSomething();
    return 0;
}

void otherFunc()
{
    doSomething();  // ERROR, doSomething() not in scope
}

void doSomething()
{
    ...
}

Конечно, есть гораздо лучшие решения для этого. Если вам нужно скрыть функцию, вы должны действительно реструктурировать свой код, переместив функции в отдельные модули так, чтобы все функции, которые должны вызывать функцию, которую вы хотите скрыть, находились в одном модуле. Затем вы можете сделать эту функцию локальной для модуля, объявив ее статической (способ C) или поместив ее в анонимное пространство имен (способ C ++).

2 голосов
/ 24 июня 2009

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

например. Я определяю некоторую структуру данных, например, дерево или график, и я не хочу раскрывать детали его внутренней реализации, например, потому что я могу хотеть изменить или изменить это. Поэтому я раскрываю функции доступа и мутатора для его элементов, а также функцию обхода элементов. Функция обхода имеет в качестве аргумента функцию, которая работает с элементом; Задача функции обхода состоит в том, чтобы выполнить функцию аргумента для каждого элемента и, возможно, каким-то образом агрегировать результаты. Теперь, когда я вызываю функцию обхода, функция аргумента обычно является какой-то специализированной операцией, которая зависит от локального состояния и поэтому должна быть определена как локальная функция. Необходимость протолкнуть функцию с переменными, которые содержат локальное состояние, снаружи, чтобы быть глобальной, или во внутренний класс, созданный специально для их хранения, - это ужасно. Но это проблема у меня с C и Java, а не с C ++.

2 голосов
/ 24 июня 2009

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

2 голосов
/ 23 июня 2009

Это прототип предварительной декларации. Возможно, если у вас есть много локальных функций или локальных функций, которые вызывают друг друга вопреки порядку определения, вам это может понадобиться.

1 голос
/ 11 января 2012

Как сказано в 3-м фрагменте этого ответа , он может помочь с затенением области.

#include <stdio.h>

void c(); // Prototype of a function named ``c''

int main() {

    c(); // call the function

    { // additional scoppe needed for C, not for C++
        int c = 0; // shadow the c function with a c integer variable
        c++;
        {
            void c(); // hide the c integer variable back with the c function
            c();
        }
        ++c;
    } //!

    return 0;
}

void c() {
    printf("Called\n");
}

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

Я все еще думаю, что это наиболее вероятная причина для этой функции, определение функций в последнее время так же, как для переменных, звучит не совсем правильно.

0 голосов
/ 24 июня 2009

Я иногда делаю это по той же причине, по которой нам рекомендуется объявлять переменные непосредственно перед их первым использованием (а не ранее), а именно, чтобы улучшить читаемость. (Да, я понимаю, что для переменных это важнее, потому что это избавляет вас от необходимости проверять, используется ли переменная до того, как вы думаете, ее первое использование). Наличие прототипа (особенно если оно более сложное, чем просто c()) близко к вызову функции улучшает читабельность. Тот факт, что особый случай C c() вводит людей в заблуждение, вызывает сожаление, но общая идея объявления функций на местном уровне имеет свои преимущества.

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

0 голосов
/ 24 июня 2009

Если вы хотите отличаться от объявления функции без параметров и создания экземпляра класса с деструктором по умолчанию, пропустите скобки.

class C
{
  public:
    void foo() {}
};


int main()
{
    // declare function d, taking no arguments, returning fresh C
    C d();

    // instantiate class (leave parenthesis out)
    C c;
    c.foo();

    // call declared function
    C goo = d();

    return 0;
}

C d()
{
    C c;
    // ..
    return c;
}
...