In template programming, static_assert
helps programmers to check constraint(s) on template arguments and generate human readable error messages on violation of constraint(s).
Consider this code,
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!
}
My thought is : if the first static_assert
fails, it means some requirement on T
doesn't meet, hence the compilation should stop, generating only the first error message — because it doesn't make much sense to continue the compilation just to generate more and more error messages, most of which often point to a single constraint violation. Hundreds of error messages, instead of just one, look very scary on the screen — I would even say, it defies the very purpose of static_assert
to some extent.
For example, if I call the above function template as:
f(std::false_type{});
GCC 4.8 generates the following:
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!
As you can see (online), that is too much of error. If the first static_assert
fails, it is very much likely that the rest of the code will also fail if compilation continues, then why continue compilation? In template programming, I'm sure many programmers don't want such cascading error messages!
I tried to solve this issue by splitting the function into multiple functions, in each checking only one constraint, as:
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
Now this generates this:
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.");
^
That is a lot of improvement — just one error message is a lot easier to read and understand (see online).
My question is,
- Why does the compilation not stop on the first
static_assert
? - Since splitting of function template and checking one constraint in each function_impl, helps only GCC and clang still generates lots of error, is there any way to improve diagnostics in a more consistent way — something which works for all compilers?