Hi!<br><br><div class="gmail_quote">On Thu, Mar 21, 2013 at 8:38 AM, Mario Lang <span dir="ltr"><<a href="mailto:mlang@delysid.org" target="_blank">mlang@delysid.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi.<br>
<br>
While experimenting with a readable bitboard initialisation syntax, I stumbled<br>
across the following code which works with GCC but is rejected by Clang:<br>
<br>
#include <initializer_list><br>
#include <cstdint><br>
<br>
namespace chess {<br>
<br>
enum class square: uint8_t {<br>
  a1, b1, c1, d1, e1, f1, g1, h1,<br>
  a2, b2, c2, d2, e2, f2, g2, h2,<br>
  a3, b3, c3, d3, e3, f3, g3, h3,<br>
  a4, b4, c4, d4, e4, f4, g4, h4,<br>
  a5, b5, c5, d5, e5, f5, g5, h5,<br>
  a6, b6, c6, d6, e6, f6, g6, h6,<br>
  a7, b7, c7, d7, e7, f7, g7, h7,<br>
  a8, b8, c8, d8, e8, f8, g8, h8<br>
};<br>
<br>
typedef std::initializer_list<square> square_initializer_list;<br>
<br>
typedef std::uint64_t bitboard;<br>
<br>
constexpr bitboard bb( square_initializer_list::const_iterator const &first<br>
                     , square_initializer_list::const_iterator const &last<br>
                     )<br>
{ return first!=last ? ((1ULL << unsigned(*first)) | bb(first + 1, last)) : 0; }<br>
<br>
constexpr bitboard bb(square_initializer_list const &init)<br>
{ return bb(begin(init), end(init)); }<br>
<br>
namespace start_position {<br>
  namespace white {<br>
    constexpr bitboard knights = bb({square::b1, square::g1});<br>
  }<br>
}<br>
<br>
}<br>
<br>
int main ()<br>
{ return chess::start_position::white::knights; }<br>
<br>
<br>
GCC 4.7 compiles this without any errors or warnings, and produces<br>
assembly which indicates that indeed, the call to bb() was evaluated<br>
at compile time.  (it also places the initializer_list content into the<br>
rodata section, which is at first sight illogical to me since it is<br>
never used at run-time, but this is something else to wonder about.)<br>
<br>
Clang complains:<br>
<br>
cx.cpp:31:24: error: constexpr variable 'knights' must be initialized by a constant expression<br>
    constexpr bitboard knights = bb({square::b1, square::g1});<br>
                       ^         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>
1 error generated.<br>
<br>
I am wondering, is this legal C++11?  Is GCC treating it too liberal, or<br>
does Clang's constexpr support miss things (I am using trunk)?<br></blockquote><div><br></div><div>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 <a href="http://llvm.org/PR15117">llvm.org/PR15117</a></div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Note that the error message could be a little more helpful.  As a user,<br>
I am wondering *why* bb({}) is not considered a constant expression (given<br>
that I explicitly declared it as such.)</blockquote><div><br></div><div>Sorry about that. With libc++ (which also doesn't have the initializer_list-as-literal-type change), we produce this:</div><div><br></div><div><div>
<font face="courier new, monospace"><stdin>:26:20: error: constexpr function never produces a constant expression [-Winvalid-constexpr]</font></div><div><font face="courier new, monospace">constexpr bitboard bb(square_initializer_list const &init)</font></div>
<div><font face="courier new, monospace">                   ^</font></div><div><font face="courier new, monospace"><stdin>:27:13: note: non-constexpr function 'begin<chess::square>' cannot be used in a constant expression</font></div>
<div><font face="courier new, monospace">{ return bb(begin(init), end(init)); }</font></div><div><font face="courier new, monospace">            ^</font></div><div><font face="courier new, monospace">/usr/include/c++/v1/initializer_list:87:1: note: declared here</font></div>
<div><font face="courier new, monospace">begin(initializer_list<_Ep> __il) _NOEXCEPT</font></div><div><font face="courier new, monospace">^</font></div><div><font face="courier new, monospace"><stdin>:31:24: error: constexpr variable 'knights' must be initialized by a constant expression</font></div>
<div><font face="courier new, monospace">    constexpr bitboard knights = bb({square::b1, square::g1});</font></div><div><font face="courier new, monospace">                       ^         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~</font></div>
<div><font face="courier new, monospace"><stdin>:31:37: note: non-literal type 'const square_initializer_list' (aka 'const initializer_list<chess::square>') cannot be used in a constant expression</font></div>
<div><font face="courier new, monospace">    constexpr bitboard knights = bb({square::b1, square::g1});</font></div><div><font face="courier new, monospace">                                    ^</font></div></div><div><br>
</div></div>