Boost logo

Boost :

Subject: Re: [boost] Static constexpr map (was: Re: [gsoc16] Can I quickly check if the below really is the best approach?)
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2016-01-17 16:51:06


On 14 Jan 2016 at 13:02, Gottlob Frege wrote:

I had a crack this weekend at a toy static_map to see if I could
improve on Louis' toy solution from
https://gist.github.com/ldionne/f7ff609f00dc7025a213. I learned many
very interesting things.

> Possibly due to limitations with pre-11 C++, I had a two-step process
> for declaring/defining the map:

It turns out this restriction remains in C++ 14, and currently C++
17. The problem is that nested braced init of heterogeneous types is
basically only possible via a C array, so either you do this:

constexpr std::pair<int, const char *> map_data[] = {
  { 5, "apple" },
  { 8, "pear" },
  { 0, "banana" }
};
constexpr auto cmap = make_static_map(map_data);

... or you do as Louis did:

constexpr auto cmap = make_static_map(
  std::make_pair(5, "apple"),
  std::make_pair(8, "pear"),
  std::make_pair(0, "banana")
);

I personally think the first form looks nicer. If C++ 17 could gain
the ability to convert nested braced init sequences of heterogeneous
types in a set of nested std::make_tuple()'s, I think that would be a
great language addition for C++ 17.

> Constexpr probably gets rid of many of those problems.

Unfortunately, constexpr as currently implemented by at least clang
3.7 and VS2015 is lazy not greedy, so currently even if all the
inputs to a constexpr expression are constexpr but the returned value
is not stored constexpr, right now the expression is not executed
constexpr by any major compiler. In code:

  // No output in assembler, so constexpr except on GCC 5.3
  constexpr auto cmap = make_static_map(map_data);

  // No abort() appears in assembler except on GCC 5.3, so this
  // was executed constexpr
  if(!cmap[8]) abort();

  // This however does cause code implementing a lookup to be
generated
  // on all compilers, so this was NOT executed constexpr. The cause
is
  // storing the result in a non-constexpr variable.
  const char *foo=cmap[5];

If you'd like to play with this yourselves, see
https://goo.gl/eO7ooa.

I was not aware of that constexpr is currently implemented lazy not
greedy before, and I still find it a highly surprising choice to not
avail of an optimisation. GCC is particularly conservative in not
making use of constexpr execution at all, even VS2015 matches clang
3.7.

Note that the C++ standard, in so far as I can tell, gives compiler
implementors the choice of what to do if the results from a constant
expression are not used in a constant expression - they can either
execute constexpr, or not. I therefore assume the compiler vendors
have good reasons for choosing to generate code when the standard
says they don't have to.

Niall

-- 
ned Productions Limited Consulting
http://www.nedproductions.biz/ 
http://ie.linkedin.com/in/nialldouglas/



Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk