Почему "конструктор-путь" объявления переменной в "for-loop" разрешен, но в "if-statement" не разрешен?

Возможный дубликат:
Почему переменные, определенные в условном выражении, не могут быть построены с аргументами?

Рассмотрим этот простой пример:

/*1*/ int main() {
/*2*/   for (int i(7); i;){break;} 
/*3*/   if (int i(7)) {}
/*4*/ }

Почему строка-2 компилируется просто отлично, в то время как строка-3 дает ошибку? Это немного странно для меня, почему if-statement в этом аспекте обрабатывается хуже, чем for-loop?

Если это конкретный компилятор - я тестировал с gcc-4.5.1:

prog.cpp: В функции 'int main()': prog.cpp: 3: 7: ошибка: ожидаемое первичное выражение перед 'int' prog.cpp: 3: 7: error: expected ')' before 'int'

Я был вдохновлен этим question

[ОБНОВЛЕНИЕ]

Я знаю, что это компилируется просто отлично:

/*1*/ int main() {
/*2*/   for (int i = 7; i;){break;} 
/*3*/   if (int i = 7) {}
/*4*/ }

[UPDATE2]

Кажется, это чисто академический вопрос, но это может быть чрезвычайно важно для таких типов, как std::unique_ptr<>, которые нельзя скопировать:

#include <memory>
int main() {
  if (std::unique_ptr<int> i = new (std::nothrow) int(7)) {
  }
  if (std::unique_ptr<int> i(new (std::nothrow) int(7))) {
  }
}

Ни один из этих двух видов не разрешен. Не уверен в синтаксисе С++ 11 {}?

Ответы

Ответ 1

Стандарт С++ не дает обоснования, но я подозреваю, что использование нотации конструктора может вызвать некоторые несоответствия. Например, поскольку объявления функций не допускаются в инструкции if, наиболее неприятный синтаксический анализ фактически означает то, что было предназначено. Например:

int f();        // function declaration (simple form or the most vexing parse)
if (int f()) {  // illegal in C++ but, when allowed, would be a zero-initialized int
}

В С++ 2011 вы можете использовать инициализацию скобок:

if (int x{f()}) {
    ...
}

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

Что касается обновления: вы можете использовать один из них:

if (std::unique_ptr<int> p = std::unique_ptr<int>(new int(1))) { ... }
if (auto p = std::unique_ptr<int>(new int(2))) { ... }
if (std::unique_ptr<int>{new int(3)}) { ... }

Кажется, есть много вариантов: -)

Ответ 2

В терминах синтаксиса причина проста.

Первым элементом оператора for являются операторы. Выражения могут создавать переменные, а также инициализировать их. Условие if является условием. Спецификация определяет, что условие может создать переменную, но только при инициализации =.

Радуйтесь, что спецификация даже позволяет создавать переменные в if вообще. Он должен иметь специальную грамматику, чтобы даже позволить этому ( "условие" отличается от "выражения" ), и это, вероятно, было чем-то унаследованным от C.

При этом С++ 11 определяет условие как способное инициализировать объявление с помощью файла braced-init-list (spec-speak для "списка инициализаторов" ). Так что это должно быть законным. Но так как VS2012 еще не поддерживает списки инициализаций...