Зачем было заключить в скобках istreambuf_iterator, чтобы заставить его работать? [Дубликат]

Давайте посмотрим на лес сначала, прежде чем смотреть на деревья.

Здесь есть много информативных ответов с большими подробностями, я не буду повторять ни одного из них. Ключ к программированию в JavaScript имеет сначала правильную ментальную модель общего исполнения.

  1. Ваша точка входа (ов) выполняется в результате события. Например, в браузер загружается тег сценария с кодом. (Соответственно, поэтому вам, возможно, придется заботиться о готовности страницы запускать ваш код, если он требует, чтобы элементы dom были сконструированы первыми и т. Д.)
  2. Ваш код выполняется до завершения, однако многие асинхронные вызовы, которые он делает, без выполнения каких-либо ваших обратных вызовов, включая запросы XHR, установку тайм-аутов, обработчиков событий dom и т. д. Каждый из этих обратных вызовов, ожидающих выполнения, будет находиться в очереди, ожидая, что их очередь будет запущена после других событий
  3. Каждый отдельный обратный вызов XHR-запроса, установленного таймаута или dom события после вызова будет завершен.

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

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

142
задан Deduplicator 23 March 2015 в 20:12
поделиться

5 ответов

Нет просветленного ответа, это просто потому, что он не определен как корректный синтаксис языка C ++ ... Так оно и есть, по определению языка.

Если у вас есть выражение внутри то оно действительно. Например:

 ((0));//compiles

Еще проще: потому что (x) является допустимым выражением C ++, а () - нет.

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

64
ответ дан Ville-Valtteri 24 August 2018 в 23:54
поделиться

Объявление функции C

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

int putchar(int);

Это позволяет вам написать такой код.

int puts(const char *);
int main() {
    puts("Hello, world!");
}

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

#include <stdio.h>

int eighty_four() {
    return 84;
}

int output_result(int callback()) {
    printf("Returned: %d\n", callback());
    return 0;
}

int main() {
    return output_result(eighty_four);
}

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

int output_result(int());

Один аргумент в конструкторе

Не знаете вон тот? Ну, позвольте мне напомнить.

A a(B());

Да, это точно такое же объявление функции. A - int, a - output_result, а B - int.

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

Если одна из этих функций не существовала или имела другой синтаксис (например, {} в C ++ 11), эта проблема никогда бы не произошла для синтаксиса с одним аргументом.

Теперь вы можете спросить, почему работает A a((B())). Ну, давайте объявим output_result бесполезными круглыми скобками.

int output_result((int()));

Это не сработает. Грамматика требует, чтобы переменная не была в круглых скобках.

<stdin>:1:19: error: expected declaration specifiers or ‘...’ before ‘(’ token

Однако C ++ ожидает стандартное выражение здесь. В C ++ вы можете написать следующий код.

int value = int();

И следующий код.

int value = ((((int()))));

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

Дополнительные аргументы в конструкторе

Конечно, один аргумент хорош, но как насчет двух? Дело не в том, что у конструкторов может быть только один аргумент. Один из встроенных классов, который принимает два аргумента, - std::string

std::string hundred_dots(100, '.');

. Все это хорошо и прекрасно (технически, он имел бы самый неприятный синтаксический анализ, если бы он был записан как std::string wat(int(), char()), но давайте будем честными - кто бы это написал? Но давайте предположим, что этот код имеет неприятную проблему. Предположим, что вам нужно все положить в круглые скобки.

std::string hundred_dots((100, '.'));

Не совсем так.

<stdin>:2:36: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
In file included from /usr/include/c++/4.8/string:53:0,
                 from <stdin>:1:
/usr/include/c++/4.8/bits/basic_string.tcc:212:5: error:   initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]
     basic_string<_CharT, _Traits, _Alloc>::
     ^

Я не уверен, почему g ++ пытается преобразовать char в const char *. В любом случае конструктор вызывался только с одним значением типа char. Нет перегрузки, которая имеет один аргумент типа char, поэтому компилятор запутан. Вы можете спросить - почему аргумент имеет тип char?

(100, '.')

Да, , здесь - запятый оператор. Оператор запятой принимает два аргумента, и дает аргумент правой стороны. Это не очень полезно, но это то, что нужно знать для моего объяснения.

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

std::string hundred_dots((100), ('.'));

Аргументы находятся в круглых скобках, а не t все это выражение. Фактически, только одно из выражений должно быть в круглых скобках, так как достаточно немного сломать C-грамматику, чтобы использовать функцию C ++. Вещи приводят нас к нулевым аргументам.

Нулевые аргументы в конструкторе

Возможно, вы заметили функцию eighty_four в моем объяснении.

int eighty_four();

Да, на это также влияет самый неприятный синтаксический разбор. Это правильное определение, и вы, скорее всего, видели, если создали файлы заголовков (и вам нужно). Добавление скобок не исправляет.

int eighty_four(());

Почему это так? Ну, () не является выражением. В C ++ вы должны поставить выражение между круглыми скобками. Вы не можете писать auto value = () в C ++, потому что () ничего не значит (и даже если бы это было так, как пустой кортеж (см. Python), это был бы один аргумент, а не ноль). Практически это означает, что вы не можете использовать сокращенный синтаксис без использования синтаксиса {} C ++ 11, так как в круглых скобках нет выражений, а C-грамматика для деклараций функций всегда будет применяться.

26
ответ дан Konrad Borowski 24 August 2018 в 23:54
поделиться

Окончательное решение этой проблемы состоит в том, чтобы перейти к синтаксису синтаксиса C + 11, если вы можете.

A a{};

http://www.stroustrup.com/C++ 11FAQ.html # равномерная-INIT

33
ответ дан leemes 24 August 2018 в 23:54
поделиться

Самые внутренние парсеры в вашем примере будут выражением, а в C ++ грамматика определяет expression как assignment-expression или другой expression, за которым следует запятая, а другая assignment-expression (Приложение A.4 - Грамматика / Выражения).

Грамматика далее определяет assignment-expression как один из нескольких других типов выражения, ни один из которых не может быть ничем (или только пропуском).

So причина, по которой вы не можете A a(()), просто потому, что грамматика этого не позволяет. Тем не менее, я не могу ответить, почему люди, которые создали C ++, не позволяли этому конкретному использованию пустых парнеров как своего рода особый случай - я бы предположил, что они предпочли бы не вставлять такой особый случай, если бы разумная альтернатива.

5
ответ дан Michael Burr 24 August 2018 в 23:54
поделиться

Вы могли бы вместо

A a(());

использовать

A a=A();
11
ответ дан user265149 24 August 2018 в 23:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: