C++0x features in VC2010 - static_assert
( n3090.pdf is the current working draft of C++0x standard, it is available at https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3090.pdf )
What we have before C++0x
It is a common task to output meaningful error message from source code based on compile-time conditions. For example, you may want to ensure that the size of your core structure has not been changed by accident.
In C++03, this is achieved by using invalid expressions (like "int array[expr ? 1 : 0];"). However, different compilers have different handling of invalid expressions. It is quite difficult to write portable code to ensure the compilation to fail.
boost has provided “BOOST_STATIC_ASSERT” which is portable, but the error message is far from user-friendly.
What we have now in C++0x
The standard committee adds a new declaration in C++0x: static assert declaration (n3090.pdf, 7/4).
The syntax is:
static_assert-declaration:
static_assert ( constant-expression , string-literal ) ;
Given a constant expression which can be converted to false, the compiler will generate an error message which contains the string specified in the declaration
1. static_assert can be used to validate the value of compile-time constant like structure size.
For example:
#define VALIDATE_TYPE_SIZE(TYPENAME, EXPECTEDSIZE) static_assert(sizeof(TYPENAME) == EXPECTEDSIZE, "The size of "#TYPENAME" is incorrect")
2. Another usage of static_assert is to validate template argument. This can be an alternative way to achieve what "concept" provides.
(BTW, because static_assert is a declaration, it can be used in both function and class)
In function:
template<typename T>
T GCD(T a, T b)
{
static_assert(std::is_integral<T>::value, "T should be an integral type");
// Calculate GCD
}
int main()
{
GCD(2, 1);
GCD("hello", "world");
}
In class:
template<typename T>
struct Complex
{
static_assert(std::is_arithmetic<T>::value, "T should be a arithmetic type");
};
Complex<int> a;
Complex<int *> b;
Known issues / limitations
1. If the string literal contains characters that are not in the basic source character set (n3090.pdf, 2.3/1), they may not appear in the error message.
That means you’d better not to use non-ASCII characters in the literal. For example, the following code snippet will show no message in VC2010:
static_assert(false, "范翔"); // my Chinese name
2. The error message of static_assert is fixed. If you want to output additional information, template can help.
For example,
template<size_t ActualSize, size_t ExpectedSize>
struct CheckTypeSize;
template<size_t Size>
struct CheckTypeSize<Size, Size> {};
CheckTypeSize<sizeof(int), 4> check;
What is special in VC2010
In VC2010, static_assert is also supported in C source.
Wide string literal is not supported. You’ll get "error C2002: invalid wide-character constant". As far as non-ASCII characters will not be displayed, this limitation is reasonable.
Known bugs in VC2010
There aren’t too many bugs related to static_assert.
Here is one that I know:
enum {e};
template<typename T>
struct A
{
};
template<>
struct A<int>
{
static const int a = e;
};
template<typename T>
struct B : A<T>
{
static_assert(A<T>::a == e, "fail");
};
int main()
{
B<int> b;
}
When you compile the code, you’ll get "error C2677: binary '==' : no global operator found which takes type '' (or there is no acceptable conversion) "
There are several conditions to repro this bug.
First, B should derive from A<T>.
Second, the primary template of A should not contain the definition of a.
Third, 'e' should be an enum member.
The workaround is fairly simple. One possible way is to use "(int)e" in the constant expression.