[cfe-dev] C++11 constexpr and initializer_list?

Richard Smith richard at metafoo.co.uk
Thu Mar 21 14:01:05 PDT 2013


Hi!

On Thu, Mar 21, 2013 at 8:38 AM, Mario Lang <mlang at delysid.org> wrote:

> Hi.
>
> While experimenting with a readable bitboard initialisation syntax, I
> stumbled
> across the following code which works with GCC but is rejected by Clang:
>
> #include <initializer_list>
> #include <cstdint>
>
> namespace chess {
>
> enum class square: uint8_t {
>   a1, b1, c1, d1, e1, f1, g1, h1,
>   a2, b2, c2, d2, e2, f2, g2, h2,
>   a3, b3, c3, d3, e3, f3, g3, h3,
>   a4, b4, c4, d4, e4, f4, g4, h4,
>   a5, b5, c5, d5, e5, f5, g5, h5,
>   a6, b6, c6, d6, e6, f6, g6, h6,
>   a7, b7, c7, d7, e7, f7, g7, h7,
>   a8, b8, c8, d8, e8, f8, g8, h8
> };
>
> typedef std::initializer_list<square> square_initializer_list;
>
> typedef std::uint64_t bitboard;
>
> constexpr bitboard bb( square_initializer_list::const_iterator const &first
>                      , square_initializer_list::const_iterator const &last
>                      )
> { return first!=last ? ((1ULL << unsigned(*first)) | bb(first + 1, last))
> : 0; }
>
> constexpr bitboard bb(square_initializer_list const &init)
> { return bb(begin(init), end(init)); }
>
> namespace start_position {
>   namespace white {
>     constexpr bitboard knights = bb({square::b1, square::g1});
>   }
> }
>
> }
>
> int main ()
> { return chess::start_position::white::knights; }
>
>
> GCC 4.7 compiles this without any errors or warnings, and produces
> assembly which indicates that indeed, the call to bb() was evaluated
> at compile time.  (it also places the initializer_list content into the
> rodata section, which is at first sight illogical to me since it is
> never used at run-time, but this is something else to wonder about.)
>
> Clang complains:
>
> cx.cpp:31:24: error: constexpr variable 'knights' must be initialized by a
> constant expression
>     constexpr bitboard knights = bb({square::b1, square::g1});
>                        ^         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 1 error generated.
>
> I am wondering, is this legal C++11?  Is GCC treating it too liberal, or
> does Clang's constexpr support miss things (I am using trunk)?
>

This was not legal when C++11 was published, but since then, the library
folks have made std::initializer_list<T> a literal type, which makes this
code legal. Clang does not yet support this: see llvm.org/PR15117


> Note that the error message could be a little more helpful.  As a user,
> I am wondering *why* bb({}) is not considered a constant expression (given
> that I explicitly declared it as such.)


Sorry about that. With libc++ (which also doesn't have the
initializer_list-as-literal-type change), we produce this:

<stdin>:26:20: error: constexpr function never produces a constant
expression [-Winvalid-constexpr]
constexpr bitboard bb(square_initializer_list const &init)
                   ^
<stdin>:27:13: note: non-constexpr function 'begin<chess::square>' cannot
be used in a constant expression
{ return bb(begin(init), end(init)); }
            ^
/usr/include/c++/v1/initializer_list:87:1: note: declared here
begin(initializer_list<_Ep> __il) _NOEXCEPT
^
<stdin>:31:24: error: constexpr variable 'knights' must be initialized by a
constant expression
    constexpr bitboard knights = bb({square::b1, square::g1});
                       ^         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<stdin>:31:37: note: non-literal type 'const square_initializer_list' (aka
'const initializer_list<chess::square>') cannot be used in a constant
expression
    constexpr bitboard knights = bb({square::b1, square::g1});
                                    ^
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130321/78621fe4/attachment.html>


More information about the cfe-dev mailing list