P1144 PMR koans

This is the fourth in a series of blog posts (I, II, III, IV) that I started after the Issaquah WG21 meeting, in order to (1) resolve the technical differences between P1144 “std::is_trivially_relocatable and the now-multiple Bloomberg papers on the topic (P2786R1, P2839R0, and the comparative analysis P2814R0), and (2) convince the rest of the C++ Committee that these resolutions are actually okay to ship.

Read More

Don’t forward things that aren’t forwarding references

Some readers of yesterday’s post may wonder about the part where I wrote:

  explicit Foo(Ts... as, Ts... bs)
    : a_(static_cast<Ts&&>(as)...),
      b_(static_cast<Ts&&>(bs)...) {}

Since we all know that std::forward<T>(t) is synonymous with static_cast<T&&>(t), why did I choose static_cast above instead of writing std::forward<Ts>(as)...?

Read More

Polymorphic types and -Wdeprecated-copy-dtor

I’m a huge proponent of clearly distinguishing value-semantic types (like string and unique_ptr<int>) from classically polymorphic, inheritance-based types (like memory_resource and exception).

  • Never inherit from a value-semantic type (and especially not from std types).

  • Never copy, move, assign, or swap a polymorphic type.

This means that polymorphic types should usually =delete all their SMFs, like this:

Read More

Fun with flat_map’s non-explicit constructors

Earlier this month I wrote: “Most constructors should be explicit” (2023-04-08). This week, while writing unit tests for libc++ flat_map (now available on Godbolt!) I encountered the following quirk of flat_map’s constructor overload set:

void print_map(std::flat_map<int, int>);

print_map({ {1, 2, 3}, {10, 20, 30} });
print_map({ {1, 2},    {10, 20} });
print_map({ {1},       {10} });
print_map({ {},        {} });

As currently specified, flat_map has twenty-six constructors; the resolution of LWG3802 will add another twelve. The two constructors relevant to this puzzle are:

flat_map(initializer_list<value_type>,
         const key_compare& = key_compare());

flat_map(key_container_type, mapped_container_type,
         const key_compare& = key_compare());

Our flat_map’s value_type is pair<const int, int>; its key_container_type and mapped_container_type are both vector<int>. Before you read on, try to guess the elements of each of the four maps above. All four lines compile; none of them is an error.

Read More

Trivial functions can still be non-nothrow (modulo compiler bugs)

Caveat lector: This post deals with extremely non-practical compiler trivia.

What happens when you =default a special member function so as to make it trivial, but also tell the compiler that it’s noexcept(false)? The Standard permits this construct ([dcl.fct.def.default]), but it doesn’t explicitly say what happens to the defaulted function — is the resulting trivial function nothrow, or not?

Read More

Escheresque parquet deformations of an aperiodic monotile

On March 20, it was announced that a team of mathematicians has found a 13-sided polygon that can tile the plane aperiodically (and that cannot tile the plane periodically), thus solving the so-called “einstein problem.” Craig Kaplan’s website has lots of details on the new shape — which so far has generally been dubbed the “hat,” even though to me it looks a lot more like a T-shirt.

Read More

Mathematical golf

Item 43 in Clement Wood’s 74-item Book of Mathematical Oddities (1927) is titled “A Matter of Golf”:

The nine holes of a mathematical golf course are 300, 250, 200, 325, 275, 350, 225, 375, and 400 yards apart. If a man could always strike the ball in a perfectly straight line exactly one of two distances, so that it could either go toward the hole, or pass over it, or drop into it, what would the two distances be that would carry him in the least number of strokes around the whole course? How many strokes would it require?

Solution below the break.

Read More

Should the compiler sometimes reject a [[trivially_relocatable]] warrant?

This is the third in a series of at least three weekly blog posts. Each post will explain one of the problems facing P1144 “std::is_trivially_relocatable and P2786R0 “Trivial relocatability options” as we try to (1) resolve their technical differences and (2) convince the rest of the C++ Committee that these resolutions are actually okay to ship.

Today’s topic is under what circumstances the compiler should “overrule” a [[trivially_relocatable]] warrant applied by the programmer.

Read More

Update on my trivial swap prize offer

In “Trivial relocation, std::swap, and a $2000 prize” (2023-02-24), I wrote:

I hereby offer a $2000 (USD) cash prize to the first person who produces an efficient and conforming implementation of std::swap_ranges, std::rotate, and std::partition — using memmove-based trivial swapping where possible, but falling back to a conforming std::swap implementation when the objects involved might be potentially overlapping subobjects.

Here (backup) is the test suite that the winning implementation will pass. […]

This generated a few helpful comments on /r/cpp, zero actual submissions, and enough motivation (coupled with those helpful /r/cpp comments) that I went off and implemented a solution myself. So as of 2023-03-03, my libc++ fork passes all eight of my test cases, and I hereby award myself the prize for libc++! ;)

In the spirit of fair play, and also because I really want to see P1144 implementations in other STLs, I’m keeping the prize open for patches against libstdc++ and Microsoft STL. If you can make libstdc++ or Microsoft STL pass the test suite, please tell me about it, and I’ll happily fork over. Offer ends December 31st, 2024, just so I don’t have to worry about forgetting to formally close the window and having someone try to claim the prize ten years from now.

Read More