Есть ли польза для объявлений функций внутри функций?

#c #c #declaration

#c #c #объявление

Вопрос:

Мы можем объявлять функции внутри функций (я хотел локальную переменную, но она анализируется как объявление функции):

 struct bvalue;
struct bdict {
    bdict(bvalue);
}
struct bvalue {
    explict operator bdict() const;
}
struct metainfo {
    metainfo(bdict);
}
void foo(bvalue v) {
    metainfo mi(bdict(v)); // parses as function declaration
    metainfo mi = bdict(v); // workaround
                            // (this workaround doesn't work in the presence of explicit ctors)
}
  

Являются ли единственными причинами «потому что это упрощает синтаксический анализатор» и «потому что так говорит стандарт», или для этого есть неясное применение?

Ответ №1:

На самом деле это вопрос C, потому что это поведение было унаследовано непосредственно от C (хотя в C ему уделяется гораздо больше внимания из-за самого неприятного синтаксического анализа).

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

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

1. В то время глобальное пространство имен было единственным для функций. Как это работает сейчас? Объявление функции, представляющее собой единый идентификатор, относится к пространству имен содержащей его функции или к глобальному? Можете ли вы объявлять функции с пространством имен?

2. Это все еще полезно. Поскольку прототип функции ограничен областью действия функции, в которой он объявлен, можно ссылаться на внешние функции и символы, не фактически загрязняя глобальное пространство имен (с помощью #include ). Рассмотрим ситуацию, когда требуется вызвать некоторую функцию, объявленную в заголовочном файле, избегая при этом ее включения и позволяя внешнему коду включать ее без конфликтов. Для крайне неубедительных наборов заголовочных файлов ( Windows.h и family, например) это особенно полезно.

Ответ №2:

Это полезно, если вам нужно использовать внешнюю функцию, имя которой будет конфликтовать с внутренней (статической) функцией или переменной в текущей единице перевода (исходном файле). Например (глупо, но это передает суть):

 static int read(int x)
{
    return bar(x);
}

static int foo()
{
    ssize_t read(int, void *, size_t);
    read(0, buf, 1);
}
  

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

1. Хм, с gcc все, что я получаю, это ошибка при попытке переопределить read в foo.

2. Ожидается, что вместо этого вы не будете использовать статическую функцию в C , безымянные пространства имен. Плюс, если это ваш предлог использовать созданную ВАМИ функцию с «неправильным именем» вместо переименования вашей функции… это действительно рискованно.

3. @AlexisWilke: Этот вопрос был помечен как C, так и C , и в C это определенно правильный путь. Я согласен, что это была плохая разметка, но я даже не заметил тега C .

Ответ №3:

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

 #include <iostream>

void f(int);
int main() {

    void f(char *);
    f(10);              // Line 7
    f("Hello world");
    return 0;
}

void f(int a) {
    std::cout << a;
}

void f(char *str) {
    std::cout << str;
}
  

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

1. Значит, вызов f(10) перед новым объявлением не выдаст никакой ошибки?

Ответ №4:

Являются ли единственными причинами «потому что это упрощает синтаксический анализатор» и «потому что так говорит стандарт»

Да, в принципе.

Все, что может быть объявлением функции, является объявлением функции.

К сожалению, это один из тех случаев, когда «просто есть».

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

1. По-видимому, полезно подделывать пространства имен в C.

2. @Martinho: Но это не поэтому.