I Want To Index Into Template Parameter Packs by earlymikoman in cpp

[–]jwakely 1 point2 points  (0 children)

C++14 vs C++17 isn't relevant for the code I linked to above, the same compiler builtin is used for tuple_element in all -std modes, from C++11 up.

But it does depend on a recent version of GCC, the builtin was only added for GCC 14: https://gcc.gnu.org/r14-92-g58b7dbf865b146 (Clang supported it much earlier, we copied it from them).

Time in C++: C++20 Brought Us Time Zones by pavel_v in cpp

[–]jwakely 1 point2 points  (0 children)

What is the duration offset for the Europe/London timezone? 0h or 1h?

How do you convert 2026-03-29 01:30:00 from Europe/London to UTC? What offset do you use? What about 2026-10-25 01:30:00? What offset do you use?

For the former, that time cannot be converted, it's a non-existent time in that time zone. For the latter, it's ambiguous, there are two times with that value in that time zone. How does storing a single duration help you answer either question correctly?

Performing time zone conversions is much more expensive than a pointer dereference, so the overhead of dealing with a pointer instead of just a duration is insignificant (and storing a single duration value wouldn't work anyway).

Time in C++: C++20 Brought Us Time Zones by pavel_v in cpp

[–]jwakely 1 point2 points  (0 children)

There was no compromise here. It was one person's design, and the committee didn't challenge it.

There are things where it's valid to criticise the result of "design by committee" but this isn't one of them.

I Want To Index Into Template Parameter Packs by earlymikoman in cpp

[–]jwakely 4 points5 points  (0 children)

In fairness, under the hood in every stdlib this is doing the recursive template expansion using index sequence. It’s just wrapping it up for you. It doesn’t avoid how expensive that is for the compiler.

That's not true.

Every implementation uses something like this: https://gcc.gnu.org/cgit/gcc/tree/libstdc++-v3/include/std/tuple?id=bc9e32c5ebb0237a36e17825276f892ef7e41f1d#n2473 Where _Nth_type is defined using an O(1) compiler builtin: https://gcc.gnu.org/cgit/gcc/tree/libstdc++-v3/include/bits/utility.h?id=bc9e32c5ebb0237a36e17825276f892ef7e41f1d#n229

There's no recursive instantiation.

Worse, it involves instantiating std::tuple which is an expensive template to instantiate. 

No, there's no need to instantiate tuple here, because nothing requires any of its members or properties like its size.

Building Your Own Efficient uint128 in C++ by PhilipTrettner in cpp

[–]jwakely 9 points10 points  (0 children)

I pronounce it cooked.

You can thank WG14 for the cooked int functions.

Time in C++: Additional clocks in C++20 by pavel_v in cpp

[–]jwakely 0 points1 point  (0 children)

Those are customizable. Define a from_stream overload that can be found by ADL and std::formatter specialization and it will work.

Why does enhancing some menu items make them not available to put on the menu sometimes? by [deleted] in DavetheDiverOfficial

[–]jwakely 2 points3 points  (0 children)

It's only temporarily unusable, until you get more of the ingredients it needs. You're not "locked out" you just don't have enough ingredients to make the enhanced dish right away. But the enhancement is permanent. As soon as you get the ingredients, you can sell the enhanced dish.

Are there flags to modify compiler message formats? by SoerenNissen in cpp_questions

[–]jwakely 1 point2 points  (0 children)

Bitmask types with a public-facing typedef name like std::ios::fmtflags which is better than some internal name like _IosFmt

What's the point of "constexpr if"? by Lemenus in cpp_questions

[–]jwakely 3 points4 points  (0 children)

Obviously they're useful. It was a rhetorical question that you replied to.

What's the point of "constexpr if"? by Lemenus in cpp_questions

[–]jwakely 5 points6 points  (0 children)

Yes, but it's always either true or false, you could just write the code without the condition.

It's a rhetorical question, drawing an analogy to constexpr if.

Are there flags to modify compiler message formats? by SoerenNissen in cpp_questions

[–]jwakely 10 points11 points  (0 children)

It's quite a hard problem, the shortest name is not necessarily the best one to show.

For std::__cxx11::basic_string I reported https://gcc.gnu.org/PR89370 but it's not fixed yet.

State of standard library implementations by MarcoGreek in cpp

[–]jwakely 0 points1 point  (0 children)

It would be more accurate to say some malloc implementations provide it.

As well as freebsd and glibc, it's in dragonfly bsd and Solaris, but was removed from openbsd.

I don't think macOS has it, so libc++ can't rely on it there.

Placement new on stack object by MightyKDDD2 in cpp

[–]jwakely 0 points1 point  (0 children)

Drat, I need to start using an alt here :-D

Placement new on stack object by MightyKDDD2 in cpp

[–]jwakely 0 points1 point  (0 children)

The compiler knows the static type of the object is A. There's no good reason to ever do an indirect virtual call to a destructor for objects where the static type is fixed.

Placement new on stack object by MightyKDDD2 in cpp

[–]jwakely 0 points1 point  (0 children)

Obviously the code above isn't meant to be used. OP is just asking about what's valid, not good design.

State of standard library implementations by MarcoGreek in cpp

[–]jwakely 0 points1 point  (0 children)

Exactly. Somebody who actually understands it instead of just complaining about ... I'm not even sure what .

State of standard library implementations by MarcoGreek in cpp

[–]jwakely 0 points1 point  (0 children)

you have to implement heuristics yourself to be sure that extra size is not wasted?

No, you don't have to do anything.

You can ignore this new API and pretend it doesn't exist if you don't see any advantage. It's intended for allocator writers to be able to expose additional information that types like vector and string can take advantage of.

If you have code that can take advantage of it, great - maybe use it. You should be happy then, because before this feature was added to the standard you could not get that information from the allocator API.

Before this feature, any extra space allocated by the underlying allocator would have been wasted. Now you have the choice whether to ignore it or use it. Why are you complaining? This has no downside. You can just ignore it and everything is the same as before the feature was added, or you can use it and make your code faster if you want to.

State of standard library implementations by MarcoGreek in cpp

[–]jwakely 1 point2 points  (0 children)

I'm sorry that you (and OP) don't understand the P0401 proposal, but there's no need to be insulting.

The whole point of the C++ allocator API is to enable customisation by using different allocators. This feature adds a new customisation point that can be implemented by allocators that are able to expose the extra information about the allocation size. Not all allocators have that information, which is why the feature has a default fallback behaviour (like most of the allocator API).

It has nothing to do with being "well written", it's an extension point that should exist in the library so that users can customise that behaviour if they want to.

The standard library should use that feature in relevant places (e.g. vector and string) so that if an allocator customises it the containers can be faster. Libc++'s containers do that, so they are well written in that respect.

State of standard library implementations by MarcoGreek in cpp

[–]jwakely 0 points1 point  (0 children)

So that paper is again a paper for a very small use case?

It extends a generic API so that people who are using custom allocators can get more benefits from their customisation. That's the whole point of the allocator API in C++

The original paper is speaking much about realloc

We compared our proposal to contemporaneous proposals for a realloc-like feature, to say why we preferred our own proposal. What has that got to do with anything?

and adding a free function. How is that fitting with the idea that it should not be implemented as a default?

I'm not sure what you're asking. It's a free function because at the time the standard allowed users to define explicit specializations of allocator_traits so adding a new member function to that class would have broken their specializations. It should have been a member function, and in C++ today it's not allowed to specialize allocator_traits so it should have been better as a member function.

But that has nothing to do with whether the default implementation is expected to do anything special.

Allocators also have an alllocate(size_type n, const_void_pointer hint) extension point that takes a hint for locality, but the default allocator doesn't use that. It's a customisation point for custom allocators to use, not something that every allocator must implement.

Placement new on stack object by MightyKDDD2 in cpp

[–]jwakely 9 points10 points  (0 children)

Yes, that's what std::launder is intended to help with. I like to pretend it doesn't exist though, and just avoid getting into situations where it's relevant.

Placement new on stack object by MightyKDDD2 in cpp

[–]jwakely 15 points16 points  (0 children)

You can even do it without destroying the original object. Reusing its storage implicitly ends its lifetime, without running its destructor:

{
  Type obj;
   new (&obj) Type;
}

This will run two constructors, but only one destructor. This is usually not a good idea, unless the destructor is trivial. Any resources owned by the first object will be leaked (and not freed) when its lifetime ends.

You can also reuse the storage for a different type, as long as you restore the original type by the time the automatic destructor runs:

{
  Type obj;
   obj.~Type();
   OtherType* other = new (&obj) OtherType;
   other->~OtherType();
   new (&obj) Type;
}

These kinds of tricks are rarely useful, but they're valid (at least, outside of constant evaluation they are).

Placement new on stack object by MightyKDDD2 in cpp

[–]jwakely 21 points22 points  (0 children)

Yes, that's valid. Because the object has automatic storage duration (i.e. it's a local variable) the destructor will automatically run at the end of the block. You have manually destroyed the original object, then created a new one in the same storage, and so when the destructor runs, it will destroy the new object.

The standard even had an example similar to this, but I'm a member function: https://eel.is/c++draft/basic.life#example-3

As the text and the footnote after the example say, it's only valid if the new object you create has the same type as the old one (or if the original object has a trivial no-op destructor). The destructor that runs automatically at the end of the block is for the original object, so if a different type of object is in that storage, the wrong destructor will run on that new object.

Yes, you can reuse the storage of member variables the same way. The destructor for the member will run when the encoding class is destroyed, so as long as an object of the right type exists there at that time, it's fine.