Some quick comments on the doc:

(1) Nice work!

(2) s/invalid_refererencing/invalid_dereferencing/. A better name for this attribute would be [[frees]] or [[deletes]], since the intent (at least in realloc's case) is that it takes ownership of the resource. `void free([[frees]] void *p)` should be annotated in the same way. However, this attribute is fairly useless in C++, because (A) we have so many different kinds of resources, and (B) we have RAII for this. If you're able to change your code to add a [[frees]] attribute, you're (in theory) also able to change it to make it take unique_ptr instead.  unique_ptr's calling convention is worse than the raw-pointer calling convention, but that's an orthogonal topic, and we already have a non-standard attribute for that (apply [[trivial_abi]] to your codebase's unique_ptr class).

(3) Overloading based on constexpr arguments: Your example here reminds me of and it has the same issue:
    struct MyString { MyString(constexpr const char *p) { assume the string's contents will never change } };
    char buf[10] = "hello";
    constexpr const char *p = buf;
    int main() {
        MyString m = p;  // initializing m with a compile-time-constant pointer to some const chars
        strcpy(buf, "goodbye");
        std::cout << m;  // oops, the string's contents have changed
C++ does not give the programmer any tools to detect whether something is a string literal or not. There have been past proposals for something like `std::string_literal`, a magic library type similar to std::initializer_list<T>, so that functions could opt into taking only string literals instead of arbitrary arrays-of-char. Of course some people would want the string's value to be compile-time-manipulable, and others would want it to be "erased" (non-compile-time) in the same way as std::initializer_list<T> in order to avoid template bloat, and actually a lot of people (N4121, P1378; P0259 is related) seem to want the length of the literal to be compile-time-available but the character values to be "erased."

(4) The printed discussion around std::variable_name() makes it pretty clear to me that they really just want std::source_location()... and in C++20 they have that.  The parenthetical "note: more than what is provided by source_location" seems wrong, since source_location does provide a `line` member.  That bullet point should be removed, or fleshed out.

(5) Compile-time string interpolation: '$' is controversial, but 'f' is standard Python, so I recommend just switching your examples to use f"strings" instead. Then you can eliminate the distracting digression.

(6) s/is_complete_type_type/is_complete_type/.  Also, this is a really really bad idea, for deep core-language reasons. See
However, also notice that the OP's problem (failing to print a nice static_assert message) is solved in C++20 because you can write ad-hoc well-formedness constraints:
    static_assert(requires{ sizeof(T); }, "type incomplete, or maybe not an object type");
    static_assert(sizeof(T) >= 4, "type too small");
Also, having an is_complete<T> trait wouldn't solve OP's problem, because what are you going to do?
    static_assert(is_complete_v<T> && sizeof(T) >= 4, "type too small");
would still fail to print the nice message; splitting it into two static_asserts just gets back a lesser version of the C++20 solution. Lesser because e.g. [T=int()] is a type where sizeof(T) doesn't compile, and yet T is a complete type. If you're trying to check that sizeof(T) is well-formed, just check that; don't mess around with abstract ideas like "completeness" that don't fully capture the sense of what you need.

(7) SOO thresholds: I recommend changing your strawman syntax to std::function<void()>::max_soo_size(). There's no reason to use a type-trait here, because (A) this isn't a place for generic dispatch and (B) this isn't a place for user customization. The right precedent is something like unordered_map.bucket_count(): an idiosyncratic implementation detail that we're exposing on the bad assumption that someone cares about it.
Why "bad assumption"? Because SOO is conditioned on more than just size.
- Some vendors' std::function will store small objects on the heap anyway, unless they are nothrow_move_constructible.
- Some vendors' std::function will store small objects on the heap anyway, unless they are trivially_move_constructible and trivially_destructible.
So, just knowing that your lambda-or-whatever is physically small enough to fit doesn't tell you that the vendor actually will use SOO. So, if you pursue this at all, maybe the right interface would be a sort of "dry run constructor," here spelled `will_hold_inline`:
    using F = std::function<void()>;
    auto t = []() { puts("whatever lambda"); };
    if (F::will_hold_inline(t)) {
        F f = t;
    } else {
        F f = t;

(8) Re inplace_function "implementation experience": You might link to the SG14 repo's implementation. ;) And I'd be interested to learn whether any of your contributors are actually using it in practice, and if not, why not, and how can we get them to switch to it. I mean, if people are avoiding an existing free library and rolling their own anyway, then how can we be sure that they wouldn't have the same reaction to a std::inplace_function after standardization?  In which case, standardizing inplace_function would be wasted effort.

(9) SOO-Enabled Vector: Differentiate between `fixed_capacity_vector<T, Cap>` (Boost's static_vector, P0843, fixed capacity, "fails" when the capacity is exceeded — and defining the behavior on "failure" is ugly) and `small_vector<T, SOOCap=SomeDefault>` (LLVM's SmallString IIRC, infinite capacity, heap-allocates when the SOO is exceeded).

(10) External Buffer Vector: Is this basically a way of "transferring ownership" of an allocation from the user into `vector`, and/or transferring ownership back out? Having a general-purpose interface for transferring allocations would in general be pretty great... but would also be a nightmare to specify, and would really lock down vendors into one specific implementation (which might not be bad).
    std::vector<char> v = {'a', 'b', 'c', 'd'};
    struct TakeResult { char *ptr; size_t len; size_t cap; };  // and also a copy of the relevant allocator?
    TakeResult tr = v.take();  // take ownership of the allocation
    std::string s;
    s.adopt(std::move(tr));  // transfer ownership of the allocation to a string!
    // actually, uh-oh, s needs to become null-terminated somehow
Or is this more like a std::pmr::vector attached to a monotonic_buffer_resource (which uses a fixed buffer first, if provided; and then switches to heap allocation)?

(11) s/heap-free/non-allocating/, if I understand correctly. I was initially confused that maybe a "heap-free function" was the opposite of a "heap-malloc function."

(12) "No-RTTI" Guarantees: Yes, `std::pmr::memory_resource::do_is_equal` used to specifically mandate the use of dynamic_cast, but LWG3000 fixed that.
Unfortunately, I notice that there's still a non-normative note on the pure virtual method that encourages use of dynamic_cast in derived user types. Maybe someone should open an LWG issue to eliminate that note.

(13) Predictable lambdas: Perhaps like this (C++17):
    auto make_lambda(std::string s) { return [s](auto t) { return s + t + "!"; }; }
    int main() {
        using LambdaType = decltype(make_lambda(""));
        alignas(LambdaType) char buffer[sizeof(LambdaType)];
        auto *lam = ::new ((void*)buffer) LambdaType( make_lambda("hello ") );
or like this (C++20) for captureless lambdas only:
    int main() {
        using LambdaType = decltype([](int x) { return x + 1; });
        alignas(LambdaType) char buffer[sizeof(LambdaType)];
        auto *lam = ::new ((void*)buffer) LambdaType();

(14) s/Suport/Support/

(15) Your [[invalidate_dereferencing]] and [[invalidate]] attributes are the same thing: they both say "this pointer gets freed."

(16) [[no_copy]]: I agree with you, this is just "Delete your copy constructor."

(17) [[rvo]]: The example is solved by "Delete your copy and move assignment operators."  Since C++17, we've had the new prvalue rules that make "copy elision" quite predictable, so it's also easy to work with non-movable types like std::lock_guard.
However, it sounds like the text doesn't match the example. The text is talking about annotating a single function's definition (not its declaration/uses) and forcing the compiler to complain if the RVO is not used. Besides P2025, there's relevant prior art in Clang's non-standard [[musttail]] attribute:
where you annotate a specific return statement and say, "This return statement must get optimization X; otherwise, error."

(18)  [[side_effect_free]], a.k.a. [[pure]], a.k.a. [[const]]... the problem here is that there are so many things "pure" might mean in C++. This is related to my point number (3), where we have a constexpr pointer to const chars and yet those chars' values can change at runtime. Same thing here. You might think `strlen` is a pure function, but in fact
    char g[] = "hello world";
    void f() { g[5] = '\0'; }
    int main() {
        const char *p = g;
        strlen(p);  // returns 11
        strlen(p);  // returns 5
So you have to start by figuring out what property the average programmer actually cares about, and then work on nailing down exactly how to specify that property. Specifying a "similar but less useful" property is... less useful.  And in practice it turns out that the average programmer doesn't care about any of these properties, because calling strlen twice is plenty fast; and if calling strlen twice ever does end up being too slow, they'll just call it once and cache the value in a local variable. ;) Giving the compiler enough information to figure out that optimization on its own has a high cost (in terms of human brain cells to make sure you got it right) and a low benefit.
I'll add that any annotation that depends on human input like this will be misused. Remember my [[trivially_relocatable]] talk? Facebook had been enabling their trivially-relocatable trait for `std::list`, but `std::list` was not in fact trivially relocatable! This led to segfaults when resizing a vector<list<int>>. If you rely on the programmer to decide whether their function ComputeSomeExpensiveOperation() is [[pure]] or not (based on some standardese definition of purity that nobody at the company has ever read, let alone understood), they will mark too much stuff as [[pure]], and eventually it will bite them.

(19) Move Semantics, page 14: IMHO a typoed "copy constructor" with signature `T(const T&&)` should be caught by clang-tidy or grep, not by any C++2b core-language change.

(20) "99% of the code to be slower" — IMO this is repeating a common misconception. The executable will be bigger due to stack-unwinding tables, but those tables go in .rodata, not .text; that shouldn't noticeably affect the speed of the non-throwing code. There's no "ooh, this next bit might throw, so set up some handlers in preparation." That just isn't how EH works anymore. It's all static precomputed tables, kept off to the side: "oops, this line seems to have thrown; let me consult my data tables and see what I'm supposed to do now."
You can't modify the person's quote, of course, but I think you should do something to indicate that it's "perception not reality."

(21)  s/amout/amount/

(22) A direct URL to some tutorial material on "nameof" would be very helpful. I have not googled it yet myself.

(23) "help catch more errors at compile time" — Obviously yes. But this is not useful feedback to the Committee. This sentence implies that game devs have a workflow where it's, like, "oh no, the game crashed at runtime... let's find the bug... okay, found it, we accidentally _______; gee, I wish the compiler had told us about that at compile time!"  The only missing piece is, what goes in the blank?  What are they doing over and over that they wish the compiler would catch?  Without telling us that, we can't really do anything to help, at compile time or otherwise.

(24) Conditional Compilation: Given that you already have `#ifdef`, what's the motivation for a new conditional-compilation facility?  Why does it need replacing?

(25) The feedback on "ASIO or not to ASIO?" seems less opinionated than I'd wish for. It sounds like the contributors don't realize that (AFAIK) Networking will be ASIO by default, and so it's not terribly useful to say "well, I don't need all of ASIO... really I just need some standard BSD-sockets stuff... I don't ask for much... never mind me..." :) because if you let the Networking group just do their own thing, I'm pretty sure you're not going to get any BSD-sockets stuff. It's all going to be io_contexts and executors and crap. (In particular, you seem to be conflating "the low-level std:: API for networking" with "the thing gamedevs will actually build on top of." What if the low-level std:: API is ASIO, and gamedevs don't want to build on top of ASIO? Would they continue to ignore it and build their own stuff next to it?)  If you positively want sockets, speak louder. And if you positively want ASIO, also speak louder. And if different contributors want both, say that. And if nobody cares, say that. But it's hard to tell what position you're taking at the moment.

(26) "We need a way to name a standard thread ... unpleasant" — Honestly, I've worked on at least two codebases that named their threads, and it was not unpleasant at all. It was like, you write one ten-line function `void set_current_thread_name(const std::string& name)` — or honestly, copy it from the last time you had to write it — and then you never look at that code again. It is the exact opposite of unpleasant.  Yes, of the function's ten lines, about five are #ifdefs; but that's not a problem at all. Write once, never look at it again.

(27) Stack size is fundamentally different from name and priority and affinity, because you cannot change it on an existing thread; it needs to be a parameter to std::thread's constructor (or something like that). Name, etc., can all be set from within the thread after it's started running. You should reflect that difference in your discussion.

(28) "some metadata from a mutex" — This is basically Clang's thread-safety attributes?
I've never used them nor have any special knowledge of them, but it sounds like what you want. It would be good to know whether any contributors have used them, whether they suffice or are lacking in some way (besides "not being standard yet"), etc.

(29) Logging — Notice that adding logging to a function probably renders it non-[[pure]]. See (18). ;)

(30) Forward Class Declarations: As long as each base class is a complete type, I think this can be implemented. If you allow incomplete base classes, then it can't be done (or at least the results are not useful to the programmer).
    struct E {};
    struct A;
    struct B : E, A {};
    B *b = f();
    A *a = b;  // this cannot be compiled because we don't know the offset of B's A subobject: it depends on whether A derives from E or not
There's also a syntactic problem: You can't express "I forward-declare that this class type exists and has no base classes." This is analogous to the problem C89 had in distinguishing between `int f();` and `int f(void);`: we've already gobbled up the obvious syntax and made it mean "this exists and I'm not saying anything about its base classes."

(31) Constrained Construction: Wat. In what way is this useful? particularly to gamedevs/embedded?

(32) Better Support of Arrays...: This is a (good) argument why not to use `std::byte` for anything ever. For normal strong enums, though, where they have named enumerators instead of being some sort of half-assed fundamental type, this is not a problem at all.
    enum class Color = { RED, GREEN, BLUE };
    Color array[] = { Color::GREEN, Color::RED };  // OK, and looks fine
    using enum Color; Color array[] = { GREEN, RED };  // OK in C++20, I think
If you really want to use std::byte with literal values, consider using a macro or a custom UDL:
    #define B(x) std::byte(x)
    auto operator""_b(int v) { return std::byte(v); }
    std::byte array[] = { B(0), B(1), B(42), B(0); };
    std::byte array[] = { 0_b, 1_b, 42_b, 0_b };
But personally I strongly recommend `unsigned char` instead. I'd like to know why the contributors feel `unsigned char` is insufficient for their needs.

(33) "Cannot add MyString(std::initializer_list) anymore" — Missing `<char>`. But also, I think the example is wrong. An initializer_list overload can coexist there just fine; std::vector<char> gets away with it. The problem would happen if the element type itself were `int`:
    MyString(int chr, int count);  // #1, pre-existing
    MyString(std::initializer_list<int>);  // #2, trying to add this one
    MyString indent{32, 4};  // used to call #1, now calls #2
Personally I strongly recommend
specifically, never using curly braces unless you mean initializer-list-initialization, which eliminates this problem completely. But I admit that in a large existing codebase with a lot of people working on it (and high turnover), enforcing this common-sense rule is not easy.

(34) Downcasting — Needs an example. I believe I understand the intent; it's talking about this, right?
    template<class MDT, class Base> MDT *downcast(Base *p) { return static_cast<MDT*>((typeid(*p) == typeid(MDT)) ? p : nullptr); }
As with (26), I agree that everyone needs this primitive in their toolbox; but it's also easy to cut and paste as soon as you need it once.

(35) Homogeneous Variadics — The example's `3,4,5` and `3,4.0,5` would be better with some spaces added.

(36) SoA to AoS — I think this is a big one. Needs a strawman syntax.

(37) Unified call syntax — I think this boat has sailed/sunk already. Personally I think member functions are great, and it sounds like gamedevs have already figured that out too. Needs an example showing why the existing solution ("just make it a member") doesn't suffice for someone's needs.
As with (24) and (32) and (33), I suspect that this bullet point is motivated by chasing after a faddish perception of what's "modern" (avoid the preprocessor, use std::byte, everything should use unicorn initialization, everything should be a free function) rather than any particular software-engineering need.

(38) "ifdef-like if constexpr" needs an example. I don't understand what "needs to be valid" means here, or what doesn't work today.

(39) "Conversions should be mostly free." Should rephrase as "mostly cost-free" or something, to avoid confusion with free-function conversion operators or whatever.

(40) "bool functions on vectors" — Does this mean filtering, like a "gather" operation? Or something else?

(41) Opt-In UB on Unsigned Overflow — I believe this can be done in a library. Has any contributor actually experimented with this? If someone provided them with a header-only library with a UB-on-overflow `ouint32`, `ouint16`, etc., would they actually try it out and provide feedback?

I almost certainly won't be at the telecon tomorrow, but I hope these comments are useful.

On Tue, Sep 7, 2021 at 10:56 AM Patrice Roy via SG14 <> wrote:
Let's do this then. See attached.

Remember: it's not a complete document yet (missing pieces), but it comes from our game programming friends and users, and represents a collection of things those I had the pleasure to speak with think would make C++ better for them. I hope it will lead to interesting discussions.


Le mar. 7 sept. 2021 à 10:50, Michael Wong <> a écrit :
Thanks Patrice, I think this document is of great interest to many people. Its entirely up to you but usually ahead of meeting sharing will enable more meaningful comments. 
I personally think this is likely one of those landmark document since the initial document from EA that started this group.
Either way, thank you for pulling this together from several major game companies and I know everyone should be aware this is a WIP and a call for collaboration.

On Tue, Sep 7, 2021 at 10:13 AM Patrice Roy <> wrote:
I plan to attend too; I have two concurrent meetings to juggle but I will try to migrate to SG14 as early as possible.

I have an incomplete but thick (30-ish pages) document to discuss, but I would simply introduce it and make it available to SG14 for study and discussion at a later meeting, since (a) too short a notice for discussion tomorrow and (b) it's still missing a few examples.

Michael : do you want me to share that document before the meeting or should I wait, since it will be more of an informational point than a technical discussion for tomorrow?


Le mar. 7 sept. 2021 à 09:48, Jens Maurer via SG14 <> a écrit :
On 07/09/2021 08.58, Andrzej Krzemienski via SG14 wrote:
> Hi SG14,
> I plan to attend the meeting on Sep 8, and present P2388R1 (Minimum Contract Support: either Ignore or Check_and_abort <>).

Michael Wong, I assume this is happening, then?


> Regards,
> Andrzej
> wt., 7 wrz 2021 o 04:38 Michael Wong < <>> napisał(a):
>     Thanks all, all these topics sound great for Games this week our Sept 8 meeting. If Patrice or Andrez plan to be there to present, I will set an agenda for this meeting. As it is Games this month, I would call on one of the Games chair to lead. 
>     Thank you.
>     On Fri, Sep 3, 2021 at 10:28 AM Tjernstrom, Staffan via SG14 < <>> wrote:
>         +1____
>         __ __
>         *From:*SG14 [ <>] *On Behalf Of *John McFarlane via SG14
>         *Sent:* Friday, 03 September, 2021 10:23
>         *To:* Low Latency:Game Dev/Financial/Trading/Simulation/Embedded Devices < <>>
>         *Cc:* John McFarlane < <>>; Gašper Ažman < <>>; Andrzej Krzemienski < <>>
>         *Subject:* Re: [SG14] No call tomorrow Aug 11____
>         __ __
>         Ahead of the agenda for next Wednesday's meeting going out, can I add P2388R1 - Minimum Contract Support: either Ignore or Check_and_abort <> for review? Andrzej would like to present it to the group and gather more feedback in person.____
>         __ __
>         On Wed, 11 Aug 2021 at 01:38, Michael Wong via SG14 < <>> wrote:____
>             Hi all, due to a well deserved summer vacation, many of our chairs are unavailable. Unless there is some topic which is urgent, we plan to cancel tomorrow and move it to the following future dates:____
>             __ __
>             Aug 11, 2021 02:00 PM ET/1800 UTC: Games Cancelled____
>             Sep 8 , 2021 02:00 PM ET/1800 UTC: Games  ____
>             Oct 13, 2021 02:00 PM ET/1800 UTC: Embedded ____
>             Nov 10, 2021 02:00 PM ET/1800 UTC: DST change/cancelled____
>             Dec 8, 2021 02:00 PM ET/1800 UTC: Finance/Low Latency ____
>             __ __
>             Cheers.____
>             _______________________________________________
>             SG14 mailing list
>    <>
>    <>____
>         ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>         IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.
>         _______________________________________________
>         SG14 mailing list
> <>
> <>
> _______________________________________________
> SG14 mailing list

SG14 mailing list
SG14 mailing list