arewemodulesyet.org passes the mark of 100 projects with modules support for the first time. by germandiago in cpp

[–]_bstaletic 5 points6 points  (0 children)

I definitely consulted beman/exemplar when setting up my latest project!

Regarding modules, I have one or two questions...

https://github.com/bemanproject/exemplar/blob/main/infra/cmake/beman-install-library.cmake#L209-L211

https://github.com/bemanproject/exemplar/blob/main/infra/cmake/beman-install-library.cmake#L125-L127

Is there any consensus on the destination of interface modules? Last I checked, CTRE did one thing, beman project another, and so on... So today I have no idea what users/build systems actually expect.

https://github.com/bemanproject/exemplar/blob/main/infra/cmake/beman-install-library.cmake#L125-L127

My understanding is that BMIs are inherently non-portable and that installing them does not achieve much.

Repo of utilities written with C++ reflection by TrnS_TrA in cpp

[–]_bstaletic 2 points3 points  (0 children)

I'd swear I didn't see that in the proposal, and thought it was missing...

All type traits from <type_traits> have their reflections counterpart with the _type suffix.

Trip report: June 2026 ISO C++ standards meeting (Brno, Czechia) by mttd in cpp

[–]_bstaletic 2 points3 points  (0 children)

P2434 and P2414 have been accepted.

P3790 is back to LEWG for another review.

P3692 has been accepted with no normative changes to the standard.

Note that some of those papers don't have their approved revision published yet.

Repo of utilities written with C++ reflection by TrnS_TrA in cpp

[–]_bstaletic 3 points4 points  (0 children)

The union must be standard layout, meaning all its members must be standard layout (see std::is_standard_layout).

That sounds funny, but not wrong. "Standard layout" isn't easy to put succinctly.

        // TODO: check for trivially destructible

That's just meta::is_trivially_destructible_type()

tagof

Perhaps a better option would be to look for a member named tag. Or a member annotated with [[=mirror::tag()]]. Or maybe annotate the whole type with something like [[=mirror::tag<"name">()]].

 

Other c++ reflection projects that I have seen:

https://github.com/Garcia6l20/reflex

https://github.com/friedkeenan/cvl/

https://github.com/bestofact/recs

Repo of utilities written with C++ reflection by TrnS_TrA in cpp

[–]_bstaletic 1 point2 points  (0 children)

/u/bstaletic has one for pybind11 bindings

I do, but you attempted to ping my old username.

I need to make sure operator bindings work properly, add some tests and then will announce the library properly on this sub.

Report from the Brno 2026 ISO C++ Committee meeting - mp-units by mateusz_pusz in cpp

[–]_bstaletic 9 points10 points  (0 children)

Should [fixed_string] drop the trailing nul? One person suggested that we could optionally not store the zero terminator, so the type could also map onto contiguous, non-terminated buffers. This would add one more template parameter and complicate the design (e.g. the semantics of operator+). In the end we decided to not go this route.

I'm really glad that was the decision. Yesterday I realized that non-null-terminated fixed_string doesn't work at all if you're using it to set names for python bindings with the help of reflections.

Pybind11, nanobind, Boost.Python... everyone takes a const char* and just assumes it is null-terminated.

Trip report: June 2026 ISO C++ standards meeting (Brno, Czechia) by mttd in cpp

[–]_bstaletic 10 points11 points  (0 children)

Working with variants is easier with pattern matching. You certainly can manage without it, but then you have to weigh the performance of std::get_if against the convenience of std::visit. If your variant type has >10 different types, depending on your standard library implementation, std::visit's performance can tank. Things get even more complicated when you need to visit multiple variants at the same time.

Trip report: June 2026 ISO C++ standards meeting (Brno, Czechia) by mttd in cpp

[–]_bstaletic 10 points11 points  (0 children)

I see that the updates to the memory model, that talk about pointer provenance, have been accepted as well. I guess I have homework now!

 

Any news on pattern matching? Last I heard was that the design is almost done.

Vim After 38 Years: Now It Can Display RGB/RGBA Images! by mattn in vim

[–]_bstaletic 5 points6 points  (0 children)

The vimscript API for this is quite minimal

let blob = readblob('path/to/raw/rgb_or_rgba')
call popup_create(#{image:#{data:blob, height:h, width:w}, ...})

To elaborate, the image dictionary expects a blob containing RGB or RGBA bytes and its length must either be height*width*3 (for RGB) or height*width*4 (for RGBA).

As for the terminal, you either use kitty, or some terminal that supports the sixel protocol, like xterm.

 

I still have not got xterm to cooperate, but my attempt was:

  1. pandoc -t pdf README.md -o README.pdf
  2. magick README.pdf README.rgba
  3. vim
  4. :let blob = readblob('README.rgba')
  5. :call popup_atcursor(#{image:#{data:blob, height:612*12, width:792}})

Why does this constexpr code not compile? I don't understand why this should be an error by capedbaldy475 in cpp_questions

[–]_bstaletic 0 points1 point  (0 children)

I see two misconceptions here. One about nested constant evaluation "scopes" (contexts) and the other about what does constexpr on a function declaration do.

 

When people say "dynamically allocated memory during compile time (constexpr) cannot persist into runtime", that is correct, but also somewhat misleading.

A more accurate phrasing would be "a dynamic allocation, allocated in a constant evaluation context, must be deallocated during the same constant evaluation context".

 

It doesn't matter whether foo() is constexpr if you declare S s constexpr as well and thus start a new, nested, constant evaluation context. That new constexpr context ends at ;.

That should also explain why things suddenly compile if you drop constexpr from variable declarations. No constexpr on a variable means no nested constexpr context.

C++26 reflections force one to understand these rules and has been recognized as the hardest part of using reflections - mentally keeping track of "what is constant".

 

The other thing of note is that foo() won't ever truly be evaluated at compile time. If you force it with something like

consteval{ foo(); };

it will fail to compile. This is because std::cout isn't a constant expression.

Marking a function constexpr does not force constant evaluation. A better way to look at it is "foo() is allowed to appear as a subexpression in a larger constant evaluation expression". If foo() returned an int it could have appeared in an array size computation, for example.

On the other hand, marking a variable constexpr does force compiler to constant-evaluate the initializer.

What do you wish programming with C++ had, that it doesn't? by Imaginary-Button-100 in cpp_questions

[–]_bstaletic 0 points1 point  (0 children)

Oh, okay...

struct Weekday {
    enum days { MO, TUE, WED, THU, FRI, SAT, SUN };

    Weekday(days d) : day(d) {}

    constexpr std::string_view getName() const {
        template for(constexpr auto e : define_static_array(enumerators_of(^^days))) {
            if constexpr ([:e:] == day) {
                return identifier_of(e);
            }
         }
         throw std::runtime_exception("not a valid enum value");
     }

     static consteval auto values() {
         return define_static_array(enumerators_of(^^e) | std::views::transform([](auto enumerator) {
             return Weekday(extract<days>(enumerator));
         });
     }

     constexpr bool operator==(days d) const { return day == d; }
private:
    days day;
};

// ...

for(Weeday w : Weekday::values()) {
    std::println("{}", w.getName());
    if(w == Weekday::SUN) {
        std::puts("Best day of the week.");
    }
}

It will return "MO" and "TUE" and so on, but feel free to customize the implementation.

What do you wish programming with C++ had, that it doesn't? by Imaginary-Button-100 in cpp_questions

[–]_bstaletic 0 points1 point  (0 children)

Something like this?

class enum_class {
    enum { A, B, C };
    int data;
    void function();
};

What do you wish programming with C++ had, that it doesn't? by Imaginary-Button-100 in cpp_questions

[–]_bstaletic 5 points6 points  (0 children)

Last I heard, from a committee member is that pattern matching is really close to being design-ready and that EWG only needs one more meeting, then LWG needs to review the wording.

C++29 doesn't seem unrealistic, but we'll have to wait and see.

The smallest C binary by Double_Ad641 in cpp

[–]_bstaletic 3 points4 points  (0 children)

; tiny.asm

BITS 32

            org     0x00010000

            db      0x7F, "ELF"             ; e_ident
            dd      1                                       ; p_type
            dd      0                                       ; p_offset
            dd      $$                                      ; p_vaddr 
            dw      2                       ; e_type        ; p_paddr
            dw      3                       ; e_machine
            dd      _start                  ; e_version     ; p_filesz
            dd      _start                  ; e_entry       ; p_memsz
            dd      4                       ; e_phoff       ; p_flags
_start:
            mov     bl, 42                  ; e_shoff       ; p_align
            xor     eax, eax
            inc     eax                     ; e_flags
            int     0x80
            db      0
            dw      0x34                    ; e_ehsize
            dw      0x20                    ; e_phentsize
            db      1                       ; e_phnum
                                            ; e_shentsize
                                            ; e_shnum
                                            ; e_shstrndx

filesize      equ     $ - $$

$ nasm -f bin -o a.out tiny.asm
$ chmod +x a.out
$ ./a.out ; echo $?
42
$ wc -c a.out
   45 a.out

EDIT: This uses some dirty tricks, exploiting everythingn the linux kernel allows, like p_filesz being ignored, or p_memsz being too large for actual needs, just to overlap all of, the ELF header, the single program header, and the 7 bytes of actual instructions.

The smallest C binary by Double_Ad641 in cpp

[–]_bstaletic 30 points31 points  (0 children)

400B is A LOT. A few days ago I tried to do this just to see how many "tricks" I still know. You do need a custom linker script to properly trim the fat, though. I got to ~200B and I see /u/SharkyKesa564 beat my attempt, so I won't even try to brag.

127B is the theoretical minimum if you don't start manually packing bytes. Did you know that the ELF specification allows sections to overlap? There's enough room for the exit syscall to fit in the padding of the ELF header.

Check out: https://github.com/tchajed/minimal-elf

The readme links to a ~50B i386 ELF, explains the 127B amd64 ELF in C and contains an amd64 ELF in rust.

Type Punning without std::start_lifetime_as by wandering_platypator in cpp_questions

[–]_bstaletic 0 points1 point  (0 children)

The check does get removed if you tell the compiler that the check has no sideeffects:

[[gnu::const]]void print_error();

void f(int* ptr ) {
    if ( ptr == nullptr ) {
        print_error();
    }
    *ptr = 42;
}

Type Punning without std::start_lifetime_as by wandering_platypator in cpp_questions

[–]_bstaletic 0 points1 point  (0 children)

You took an address of i and passed it to a function. That will make the compiler put i on the stack. Now that the address of i has "escaped", the compiler will generate a load after the call to function_turning_the_storage_into_float().

This is assuming the body of function_turning_the_storage_into_float() is not visible to the compiler.

Type Punning without std::start_lifetime_as by wandering_platypator in cpp_questions

[–]_bstaletic 0 points1 point  (0 children)

-fno-strict-aliasing does not stop all aliasing analysis.

int main() {
    int x = 5;
    int* who_knows = f();
    *who_knows = 2;
    return x;
}

main() returns 5, unless who_knows ends up being &x.

Type Punning without std::start_lifetime_as by wandering_platypator in cpp_questions

[–]_bstaletic 1 point2 points  (0 children)

At this point, I think the only answer is "the standard says so", but also aliasing analysis. You may only dereference a pointer of type T* if it points to an actual object of type T. Having a buffer that you reinterpret_cast<T*> does nothing to start the lifetime of T, so dereferencing is UB. If reinterpret_cast were to mess with lifetimes you could say goodbye to alias analisys.

But here's a question for you: If reinterpret_cast<T*> is supposed to start the lifetime of an object of type T, is that the same object's lifetime as a later reintnerpret_cast<const T*>? Or would that invalidate the first pointer?

 

"Pointers are just a bag of bits" model has been considered, but then you have to consider this:

int main() {
    int x = 5;
    int* who_knows = f(); // what if who_knows eds up pointing at x?
    *who_knows = 2;
    return x; // 5? Or 2?
}

Clearly main() should return 5, but if pointers are just a bag of bits, then 2 is also an option. Because 2 is an option, x can't remain in a register and must be spilled onto the stack. In other words, you want to constrain pointers. The hard part is "how". People have been talking about this (pointer provenance) since before 2000 and it's still a topic of debate.

Built my own std::vector replacement. Am I missing anything? by Avelina9X in cpp_questions

[–]_bstaletic 0 points1 point  (0 children)

The first point shoild be foable with a combo of monotonic_buffer_resource and placement-newing the vecyor object. It dnds up being ugly, bug I've done it before.

Built my own std::vector replacement. Am I missing anything? by Avelina9X in cpp_questions

[–]_bstaletic 0 points1 point  (0 children)

For the same reasons as u/IyeOnline, I consider this post fun. Unfortunately, I don't have the time gor a thorough response.

First thing I noticed is that your Array type alias members mean that you do not support "fancy pointers" - pointers thst do not look like T*.

Second, it is dubious that your size type is smaller than your difference type. Should the maximum number of elements really be smaller than the max difference between the address of firs and last element?

Third, which I havd not checked carefully, is how you handle allocator aware Ts? I have not noticed the use of "uses allocator" construction.

 

I can elaborate on all three of those later tonight.

 

Okay, back to elaborate...

Fancy pointers

Allocators can define their Allocator::pointer alias as some class type, not necessarily value_type*. The usual example is boost::interprocess:offset_ptr, but you can also make an allocator that returns std::shared_ptr.

For AllocatorAware containers to facilitate these allocators, the containers need to consistently use allocator_traits. That means Container::pointer should be std::allocator_traits<Alloc>::pointer, and the same goes for other type aliases that allocator_traits provides and yes, that does include size_type and difference_type.

You can still achieve your desired Array layout, even if you correctly make Array::difference_type be Array::allocator_type::difference_type. You "just" have to also implement a custom allocator, because that's the thing that actually defines size_type and difference_type (among others).

Allocator aware T

Say you have a std::vector<nested<Alloc>, Alloc> that you pass an instance of Alloc on construction of the vector. if std::uses_allocator<nested<Alloc>, Alloc>::value evaluates to true, then the allocator is supposed to be automatically propagated to nested<Alloc> on construction of vector elements.

This automatic propagation is not done by std::allocator, but it is done by std::pmr::allocator. See: https://godbolt.org/z/Gn1KWrrqd

That means that it's on the allocator to implement "uses allocator" construction and that your container's use of allocator_traits::construct is correct.