Точка оценки спецификации исключения - PullRequest
0 голосов
/ 20 мая 2018

Рассмотрим следующие фрагменты кода:

Версия (1)

void q() {}
class B {
  void f() noexcept(noexcept(q())) {q(); }
  decltype(&B::f) f2;
};

Версия (2)

void q() {}
class B {
  void f() noexcept(true) {q(); }
  decltype(&B::f) f2;
};

Версия (3)

void q() {}
class B {
  void f() noexcept {q(); }
  decltype(&B::f) f2;
};

Все версии GCC компилируют эти фрагменты кода без каких-либо ошибок или предупреждений (включая версию с транком).Все версии Clang, которые поддерживают C ++ 17, запрещают версию (1) и (2), но не версию (3), со следующей ошибкой:

<source>:4:16: error: exception specification is not available until end of class definition

  decltype(&B::f) f2;

               ^

Примите во внимание, что стандарт определяет noexcept как эквивалент noexcept(true) [кроме.spec].Таким образом, версия (2) и версия (3) должны быть эквивалентны, что они не для лязг.

Таким образом, следующие вопросы: В какой момент спецификации исключений должны быть оценены в соответствии с C ++ 17стандарты?И, если некоторые приведенные выше коды являются недействительными, что является рациональным?


Абстрактный фон для тех, кто интересуется:

template <typename F>
struct result_type;

template<typename R, typename C, typename... Args>
struct result_type<R(C::*)(Args...)> {
  using type = R;
}; // there may be other specializations ...

class B {
  int f() noexcept(false) { return 3; }
  typename result_type<decltype(&B::f)>::type a;
};

Этот код должен быть действительным, по крайней мере, доC ++ 14, потому что noexcept не был частью типа функции (для clang он скомпилирован до версии 3.9.1).Для C ++ 17 нет способа сделать это.

Ответы [ 2 ]

0 голосов
/ 07 августа 2018

Я сам отвечу на этот вопрос со ссылками на все соответствующие ресурсы.

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

Clang приблизительно корректен для отклонения этого кода.

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

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

Ошибка LLVM 37559 , но также смотрите Группы Google , CWG 361 , CWG 1330

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

Таким образом, вывод состоит в том, что все примеры плохо сформированы, даже если это не желаемое поведение.

0 голосов
/ 20 мая 2018

Это результат CWG 1330 .

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

Это ставит нас в ситуацию, когда:

void q() {}
class B {
  void f() noexcept(noexcept(q())) {q(); }
//                  ~~~~~~~~~~~~~
//                  evaluated in the context of complete B

  decltype(&B::f) f2;
//~~~~~~~~~~~~~~~
//cannot wait until B is complete to evaluate
};

Нам нужно знать decltype(&B::f) для обработкиобъявление B::f2, но для того, чтобы узнать этот тип, нам нужно знать, что такое noexcept-спецификатор из B::f (потому что теперь это часть системы типов), но для того, чтобысделайте , что , нам нужно оценить noexcept-спецификатор в контексте полного B.

Программа неверно сформирована, clang верен.

...