C++ Logo

sg14

Advanced search

Re: [SG14] No call tomorrow Aug 11

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Tue, 7 Sep 2021 13:43:42 -0400
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
https://quuxplusone.github.io/blog/2021/08/07/p2266-field-test-results/#libreoffice-ostring
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
https://stackoverflow.com/questions/1625105/how-to-write-is-complete-template
https://reviews.llvm.org/D108645
https://godbolt.org/z/nr3dPY7va
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*.
https://quuxplusone.github.io/blog/2019/03/27/design-space-for-std-function/#sbo-affects-semantics
- 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;
        assert(f.is_held_inline());
    } else {
        F f = t;
        assert(!f.is_held_inline());
    }

(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
    assert(v.empty());
    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.
https://cplusplus.github.io/LWG/issue3000
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.
https://eel.is/c++draft/mem.res.class#mem.res.private-note-1

(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 ")
);
        (*lam)("world");
        lam->~LambdaType();
    }
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();
        (*lam)(42);
        lam->~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:
https://reviews.llvm.org/D99517
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
        f();
        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?
https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
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
https://quuxplusone.github.io/blog/2019/02/18/knightmare-of-initialization/#simple-guidelines-for-variable-i
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.
–Arthur



On Tue, Sep 7, 2021 at 10:56 AM Patrice Roy via SG14 <sg14_at_[hidden]>
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.
>
> Cheers!
>
> Le mar. 7 sept. 2021 à 10:50, Michael Wong <fraggamuffin_at_[hidden]> 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 <patricer_at_[hidden]> 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?
>>>
>>> Cheers!
>>>
>>> Le mar. 7 sept. 2021 à 09:48, Jens Maurer via SG14 <
>>> sg14_at_[hidden]> 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 <
>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2388r1.html>).
>>>>
>>>> Michael Wong, I assume this is happening, then?
>>>>
>>>> Jens
>>>>
>>>>
>>>> > Regards,
>>>> > Andrzej
>>>> >
>>>> > wt., 7 wrz 2021 o 04:38 Michael Wong <fraggamuffin_at_[hidden] <mailto:
>>>> fraggamuffin_at_[hidden]>> 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 <
>>>> sg14_at_[hidden] <mailto:sg14_at_[hidden]>> wrote:
>>>> >
>>>> > +1____
>>>> >
>>>> > __ __
>>>> >
>>>> > *From:*SG14 [mailto:sg14-bounces_at_[hidden] <mailto:
>>>> sg14-bounces_at_[hidden]>] *On Behalf Of *John McFarlane via SG14
>>>> > *Sent:* Friday, 03 September, 2021 10:23
>>>> > *To:* Low Latency:Game
>>>> Dev/Financial/Trading/Simulation/Embedded Devices <
>>>> sg14_at_[hidden] <mailto:sg14_at_[hidden]>>
>>>> > *Cc:* John McFarlane <john_at_[hidden] <mailto:
>>>> john_at_[hidden]>>; Gašper Ažman <gasper.azman_at_[hidden] <mailto:
>>>> gasper.azman_at_[hidden]>>; Andrzej Krzemienski <akrzemi1_at_[hidden]
>>>> <mailto:akrzemi1_at_[hidden]>>
>>>> > *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 <
>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2388r1.html>
>>>> 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 <
>>>> sg14_at_[hidden] <mailto:sg14_at_[hidden]>> 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
>>>> > SG14_at_[hidden] <mailto:SG14_at_[hidden]>
>>>> > https://lists.isocpp.org/mailman/listinfo.cgi/sg14 <
>>>> https://lists.isocpp.org/mailman/listinfo.cgi/sg14>____
>>>> >
>>>> >
>>>> >
>>>> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>>>> >
>>>> > 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_at_[hidden] <mailto:SG14_at_[hidden]>
>>>> > https://lists.isocpp.org/mailman/listinfo.cgi/sg14 <
>>>> https://lists.isocpp.org/mailman/listinfo.cgi/sg14>
>>>> >
>>>> >
>>>> > _______________________________________________
>>>> > SG14 mailing list
>>>> > SG14_at_[hidden]
>>>> > https://lists.isocpp.org/mailman/listinfo.cgi/sg14
>>>> >
>>>>
>>>> _______________________________________________
>>>> SG14 mailing list
>>>> SG14_at_[hidden]
>>>> https://lists.isocpp.org/mailman/listinfo.cgi/sg14
>>>>
>>> _______________________________________________
> SG14 mailing list
> SG14_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg14
>

Received on 2021-09-07 12:43:58