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

smertigdon
smertigdon

При написании библиотек/вспомогательных шаблонных классов разработчики часто используют 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 времени компиляции. А раз у нас будет более удобное метапрограммирование, значит нужны и информативные сообщения об ошибках!

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

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

Да, можно зациклиться. Впрочем, template-depth тоже придуман не просто так :)
smertigdon
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).
Все предложения