Partilhar via


C++0x features in VC2010 - static_assert

Summary Page 

 

( 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.