static_assert without C++11 and with a message?

Hi there,

I was looking into libc++, and noticed the implementation of static_assert
for pre-c++11 compilers.

Inside of the _LIBCPP_HAS_NO_STATIC_ASSERT ifdef, there is a typo (__t
should be __m I presume?), but even when that is fixed, I can't see how the
static assert macro could work.

It would expand to

typedef __static_assert_check<unsigned> "some message";

in both the true and false case. For the false case it fails to compile the
__static_assert_check<unsigned> already, but for the true case it also fails
to compile. How should that work?

Thanks,

Steve.

Hi there,

I was looking into libc++, and noticed the implementation of static_assert
for pre-c++11 compilers.

Inside of the _LIBCPP_HAS_NO_STATIC_ASSERT ifdef, there is a typo (__t
should be __m I presume?),

Nope.

but even when that is fixed, I can't see how the
static assert macro could work.

It would expand to

typedef __static_assert_check<unsigned> "some message";

in both the true and false case. For the false case it fails to compile the
__static_assert_check<unsigned> already, but for the true case it also fails
to compile. How should that work?

For me, preprocessing this in C++03 mode:

#include <__config>

int main()
{
    const int i = 0;
    static_assert(i == 0, "");
}

Yields:

typedef __char16_t char16_t;
typedef __char32_t char32_t;

namespace std {
  inline namespace __1 {
  }
}

template <bool> struct __static_assert_test;
template <> struct __static_assert_test<true> {};
template <unsigned> struct __static_assert_check {};

int main()
{
    const int i = 0;
    typedef __static_assert_check<sizeof(__static_assert_test<(i == 0)>)> __t6;
}

Since i == 0 is true, __static_assert_test<true> is instantiated, which has a complete type. So __t6 is a typedef for:

    __static_assert_check<sizeof(__static_assert_test<true>)>

If i != 0, an attempt would be made to form a typedef to:

    __static_assert_check<sizeof(__static_assert_test<false>)>

but __static_assert_test<false> is an incomplete type, and thus a compile time error will be emitted.

Is this not the behavior you're seeing?

Howard

This isn't quite right: the first argument to static_assert is
contextually converted to bool. So a more correct emulation would
produce:

typedef __static_assert_check<sizeof(__static_assert_test<bool(i ==
0)>)> __t6;

Testcase:

  int n;
  static_assert(&n, "");

Right. But your fix doesn't seem to be working:

test.cpp:4:2: error: non-type template argument of type 'bool' is not an integral constant expression
static_assert(&n, "");
^~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode45-DP1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/__config:378:63: note: expanded from
      macro 'static_assert'
    typedef __static_assert_check<sizeof(__static_assert_test<(bool(__b))>)> \
                                                              ^~~~~~~~~~~
1 error generated.

Howard

Hah, of course, the constant expression rules are tighter in C++98 too
:slight_smile: Depending on how much you want to emulate C++11 semantics, you
could either stick with what you have, or enable full folding with the
__builtin_constant_p(...) ? ... : ... hack.

Yeah. I'm kind of hoping for C++98/03 to just gracefully fade away. A lot of standards effort was put into making C++11 backward API compatibility and hopefully people will just migrate. There's a lot of attempted C++11 emulation of libc++ in C++03 mode. static_assert is the best of it. Variadic templates is the worst. And in other places such as move semantics and <tuple>, no attempt is made at all.

The message is: migrate to -std=c++11 ! It is worth it! :slight_smile:

Howard

Howard Hinnant wrote:

Boost has a C++98 static assert with message, but you
have_to_make_the_message_a_valid_identifier.

<http://www.boost.org/doc/libs/1_49_0/libs/mpl/doc/refmanual/assert-msg.html>

John

<nod> I'd be more motivated to create a perfect static_assert in C++03 mode if -std=c++11 was not just so darned easy and useful for so many things! :slight_smile:

Howard