cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
89 stars 0 forks source link

Ослабить требование к второму аргументу в static_assert #222

Closed apolukhin closed 11 months ago

apolukhin commented 3 years ago

Перенос предложения: голоса +43, -0 Автор идеи: smertigdon

Текущая версия стандарта требует, чтобы второй аргумент static_assert'а являлся string literal, что не позволяет использовать в нём constexpr char*

При написании библиотек/вспомогательных шаблонных классов разработчики часто используют static_assert для контроля входных данных и промежуточных результатов. Однако сообщения, выдаваемые при нарушении обязательств, должны быть строковыми литералами. Так как сама проверка может происходить где-то в недрах библиотеки, то и выдать универсальное понятное сообщение не всегда представляется возможным.

Предложение состоит в том, чтобы разрешить использование constexpr char* значений в качестве второго аргумента static_assert. Это позволит писать код с более информативными сообщениями об ошибках времени компиляции.

Представим старый код:

#include <type_traits>
#include <string>

template <class... Args>
class foo {
  static_assert(std::conjunction_v<std::is_pod<Args>...>, "All args must be pod!");
};

int main() {
    foo<int, std::string, float> f;
}

Сообщение об ошибке будет соответствующим. А теперь представим, что каждый из аргументов - это синоним типа и их более десятка. И какой-то из них после очередного рефакторинга перестал быть POD. На поиск источника проблемы уйдёт драгоценное время.

А теперь новый код, если предложение примут:

template <class... Args>
class foo {
  static_assert(std::conjunction_v<std::is_pod<Args>...>, compile_time_joiner("All args must be pod, but ", type_name<find_non_pod<Args...>>, " isn't"));
};

Преимущество очевидно. На данный момент существует несколько реализаций compile-time строк, множество алгоритмов для работы с типами, поэтому реализация compile_time_joiner, type_name<..> и find_non_pod<...> - не проблема. С учётом того, что идёт активная работа над рефлексией, то упростится и работа с типами. Там подоспеет и аналог sprintf времени компиляции. А раз у нас будет более удобное метапрограммирование, значит нужны и информативные сообщения об ошибках!

apolukhin commented 3 years ago

webreh, 18 сентября 2017, 17:54 Совершенно не очевидно, должно ли быть сообщение правой части инстанцировано при выполнении условия, как должно проверяться и что должно происходить, если инстанцирование сообщения об ошибке приводит к провалу или новому сообщению об ошибке

smertigdon, 28 ноября 2017, 11:53 webreh, вопрос хороший, но проблем особых не вижу. На данный момент инстанцирование чего-либо в compile-time не должно иметь побочных эффектов. Все хаки, опирающиеся на факт инстанцирования - дефекты стандарта (привет, friend+loophole). Я к тому, что выбор между инстанцированием правой части всегда или только при срабатывании assert'а - это лишь вопрос вкуса, на который нужно один раз ответить. Лично я пока не вижу причин против инстанцирования только при срабатывании. Пытаемся инстанцировать правую часть - ну отлично. Возникла ошибка при инстанцировании? Прерываем. В чём отличие от рекурсивного инстанцирования шаблонов?

Алгоритм элементарный:

  1. Что-нибудь инстанцируем, наткнулись на static_assert
  2. Если первый аргумент static_assert'а вычислился с результатом true, goto 4. Иначе, вычисляем второй аргумент.
  3. Пытаемся вычислить второй аргумент static_assert'а. Если в процессе попадём на static_assert, goto 0.
  4. Выводим в консоль вычисленную строку и прерываем компиляцию.
  5. Продолжаем вычисления/компиляцию

Да, можно зациклиться. Впрочем, template-depth тоже придуман не просто так :)

apolukhin commented 11 months ago

Приняли в C++26 в https://wg21.link/P2741