C++0x features in VC2010 – static_assert


Summary Page 


 


(n3090.pdf is the current working draft of C++0x standard, it is available at http://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.

Comments (0)

Skip to main content