Live data from Hacker News

Fun with C++26 reflection: Keyword Arguments

pydong.org

141–147 of 147 posts

Re: Fun with C++26 reflection: Keyword Arguments

#141
post #131

Earlier quoted context omitted.

Takes a bunch of manual work per POD, that's the gist of it. Fundamentally, if I have struct { int x = 3; std::string y = "bla"; } I want the json to look like { x: 3, y: "bla" } without writing any code specific to the struct, and have it work bidirectionally. This is currently not possible because of a lot of reasons, but most trivially because the names "x" and "y" do not even exist anymore in your compiled code.

This is absolutely possible, even currently - albeit in a very much non-portable way. For example boost::pfr and my own (wip) repr library have the required machinery for this.

Interesting! There seem to be a lot of limitations though:

> Boost.PFR library works with types that satisfy the requirements of SimpleAggregate: aggregate types without base classes, const fields, references, or C arrays:

And in general seems to be dependent on C++20 for getting field names.

Do you know how this works? Initializer lists seem somehow involved.

Re: Fun with C++26 reflection: Keyword Arguments

#142
post #93

Earlier quoted context omitted.

I think it is easy enough to be a potential footgun [0]: struct A { A(A*);}; struct B { A a1; A a2; }; void f() { B b{.a1 = A(nullptr), .a2 = A(&b.a1) }; } [0] https://godbolt.org/z/cGaxzh17T

That's a stretch to call it "easy enough", you are explicitly pointing the gun at your foot. That `b.a1` might not be explicitly UB, but that's quite suspect when b's lifetime didn't start yet. Accessing members through `this` in constructors have some special allowance to not make that UB.

Good point, I should've used direct initialization in this example.

  struct A { 
    int x;
    A(A *a) { if (a) a->x = 42;}
  };

  struct B {
    A a1;
    A a2;
  };

  void f()
  {
    B b{.a1{nullptr}, .a2{&b.a1} };
  }
This code is valid.

Now if I change the struct definition to

  struct B {
    A a2;
    A a1;
  };
it will become UB. Luckily it won't compile because of the difference between the order of declaration and the order of designated initializers.

The alternative way is to always initialize the sub-objects in the order of designated initializers (what do we do if not all initializers are provided?), but this would mean that the order of constructor calls wouldn't match the (reversed) order of destructor calls. Or we would need to select the destructor dynamically based on the way the object was initialized.

https://godbolt.org/z/MPoqEhTvf

Re: Fun with C++26 reflection: Keyword Arguments

#143
post #110
post #90

Earlier quoted context omitted.

In a general case you can't do that with separate compilation. [0] struct A { A(A*); }; A* f(struct B *b); struct B { A a1; A a2; B(): a1(f(this)), a2(f(this)) {} }; //in a different translation unit A* f(B *b) { return &b->a1; //or a2, we don't know } [0] https://godbolt.org/z/xMb64ssYK

Your code snippet does not use the designated initializer feature that this comment thread is talking about. Furthermore your code possibly contains undefined behavior depending on the behavior of the constructor of A.

As I stated above, it's the same kind of situation. See my another comment in this thread for an example with designated initializers.

>your code possibly contains undefined behavior

Only if f() returns a pointer to a2 (which is my point). Or did you imply that in the case when f() returns a pointer to a1 and it gets passed to the constructor of a1, provenance matters?

Re: Fun with C++26 reflection: Keyword Arguments

#144

Earlier quoted context omitted.

i believe this is standard since c99 you do have to cast it, though: `foo((vec2){.x=2, .y=2})` the oldest MSVC on godbolt also accepts it, so it should be very portable as long as you're not using some embedded compiler from the mid 90s a related fun thing is that you can pass it by pointer, and the lifetime will extend until the function is done: `foo(&(vec2){ .x=2, .y=2 })`

Smells like UB. Is this defined in the standard?

C99 spec, section 6.5.2.5: https://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf

> 6. The value of the compound literal is that of an unnamed object initialized by the initializer list. If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

it's valid until the end of the block. so, if the function returns the pointer, you can even use that until the end of the block

there's actually an example in the spec, on that page:

> drawline(&(struct point){.x=1, .y=1}, &(struct point){.x=3, .y=4});

Re: Fun with C++26 reflection: Keyword Arguments

#145

Earlier quoted context omitted.

That's a stretch to call it "easy enough", you are explicitly pointing the gun at your foot. That `b.a1` might not be explicitly UB, but that's quite suspect when b's lifetime didn't start yet. Accessing members through `this` in constructors have some special allowance to not make that UB.

Good point, I should've used direct initialization in this example. struct A { int x; A(A *a) { if (a) a->x = 42;} }; struct B { A a1; A a2; }; void f() { B b{.a1{nullptr}, .a2{&b.a1} }; } This code is valid. Now if I change the struct definition to struct B { A a2; A a1; }; it will become UB. Luckily it won't compile because of the difference between the order of declaration and the order of designated initializers.…

My gripe was not the form of initialization of the elements, but forming `b.a1` before `b`'s lifetime has started. It hasn't started before all of the elements are initialized.

Re: Fun with C++26 reflection: Keyword Arguments

#146

Earlier quoted context omitted.

Good point, I should've used direct initialization in this example. struct A { int x; A(A *a) { if (a) a->x = 42;} }; struct B { A a1; A a2; }; void f() { B b{.a1{nullptr}, .a2{&b.a1} }; } This code is valid. Now if I change the struct definition to struct B { A a2; A a1; }; it will become UB. Luckily it won't compile because of the difference between the order of declaration and the order of designated initializers.…

My gripe was not the form of initialization of the elements, but forming `b.a1` before `b`'s lifetime has started. It hasn't started before all of the elements are initialized.

But do we need the lifetime of b to be started? Isn't it enough that a1's lifetime is started? Taking of address of a1 happens after that. [0]

Upd:

There is an interesting sentence in [class.cdtor] but I don't think it applies here because B has no constructors:

"For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior."[1]

[0] https://eel.is/c++draft/dcl.init.aggr#7

[1] https://eel.is/c++draft/class.cdtor#1

Re: Fun with C++26 reflection: Keyword Arguments

#147
post #110

Earlier quoted context omitted.

Your code snippet does not use the designated initializer feature that this comment thread is talking about. Furthermore your code possibly contains undefined behavior depending on the behavior of the constructor of A.

As I stated above, it's the same kind of situation. See my another comment in this thread for an example with designated initializers. >your code possibly contains undefined behavior Only if f() returns a pointer to a2 (which is my point). Or did you imply that in the case when f() returns a pointer to a1 and it gets passed to the constructor of a1, provenance matters?

Actually, provenance matters:

"During the construction of an object, if the value of the object or any of its subobjects is accessed through a glvalue that is not obtained, directly or indirectly, from the constructor's this pointer, the value of the object or subobject thus obtained is unspecified." [0]

Reading an unspecified value isn't UB, that's good, but I don't understand why the standard says 'unspecified' because it clearly can be indeterminate if a sub-object hasn't been initialized yet.

[0] https://eel.is/c++draft/class.cdtor#2

Post reply on HN