В программировании шаблонов static_assert
помогает программистам проверять ограничения на аргументы шаблона и генерировать человека, читаемого сообщения об ошибках при нарушении ограничений (-ов).Улучшение диагностики с помощью static_assert
Рассмотрим этот код,
template<typename T>
void f(T)
{
static_assert(T(), "first requirement failed to meet.");
static_assert(T::value, "second requirement failed to meet.");
T t = 10; //even this may generate error!
}
Моя мысль: если первый static_assert
выходит из строя, это означает некоторые требования по T
не соответствует, следовательно, компиляция должна прекратить, генерируя только первый сообщение об ошибке —, потому что не имеет смысла продолжать компиляцию, чтобы генерировать все больше сообщений об ошибках, большинство из которых часто указывает на одиночный ограничение violati на. Сотни сообщений об ошибках, а не только один, выглядят очень страшно на экране — Я бы даже сказал, что это не совсем то, что цели от static_assert
.
Например, если я называю выше шаблон функции, как:
f(std::false_type{});
GCC 4.8 генерирует следующее:
main.cpp: In instantiation of 'void f(T) [with T = std::integral_constant<bool, false>]':
main.cpp:16:24: required from here
main.cpp:7:5: error: static assertion failed: first requirement failed to meet.
static_assert(T(), "first requirement failed to meet.");
^
main.cpp:9:5: error: static assertion failed: second requirement failed to meet.
static_assert(T::value, "second requirement failed to meet.");
^
main.cpp:11:11: error: conversion from 'int' to non-scalar type 'std::integral_constant<bool, false>' requested
T t = 10; //even this may generate error!
Как вы можете видеть (online), то есть слишком много ошибок , Если первый static_assert
терпит неудачу, очень вероятно, что остальная часть кода будет также сбой, если компиляция продолжается, то зачем продолжать компиляцию? В программировании шаблонов я уверен, что многие программисты не хотят таких каскадных сообщений об ошибках!
Я попытался решить эту проблему путем расщепления функции на множество функций, в каждой проверке только одно ограничение, как:
template<typename T>
void f_impl(T); //forward declaration
template<typename T>
void f(T)
{
static_assert(T(), "first requirement failed to meet.");
f_impl(T());
}
template<typename T>
void f_impl(T)
{
static_assert(T::value, "second requirement failed to meet.");
T t = 10;
}
f(std::false_type{}); //call
Теперь это порождает это:
main.cpp: In instantiation of 'void f(T) [with T = std::integral_constant<bool, false>]':
main.cpp:24:24: required from here
main.cpp:10:5: error: static assertion failed: first requirement failed to meet.
static_assert(T(), "first requirement failed to meet.");
^
То есть много улучшения — просто одно сообщение об ошибке намного легче читать и понимать (см. online).
Мой вопрос,
- Почему компиляция не останавливается на первом
static_assert
? - Поскольку расщепление шаблона функции и проверки одно ограничение в каждом function_impl, помогает только GCC и лязг ещеgenerates lots of error, есть ли способ улучшить диагностику более последовательно — то, что работает для всех компиляторов?
В GCC и Clang есть возможность остановиться после одной ошибки, но это не слишком хорошо работает из моего опыта, так как некоторые ошибки имеют жизненно важную информацию. Конечно, я не думаю, что это совсем то, что вам нужно: p – chris
Эта опция -Wfatal-errors, и именно то, что я бы рекомендовал (кроме случаев, когда комментарий @ chris прав, и это исключает важную информацию). Я думаю, что компиляторы считают, что ответственность за среду разработки (возможно, IDE) проявляется в презентабельной форме. – hvd
@hvd, Clang действительно отлично поработал, когда я ловил пример. Раньше я использовал его только с GCC. В любом случае, как один пример, посмотрите, как GCC отключает список кандидатов: http://coliru.stacked-crooked.com/a/4fdcf6e8bd878ffb – chris