Entt: Default example in README is confusing, should be explicit about emplace and forwardargs

Created on 19 Nov 2020  路  6Comments  路  Source: skypjack/entt

In the example in the README, you have a struct without a manual constructor - only default constructor - but then when you use emplace, you pass in arguments of two floats, which I presume are intended to set dx and dy:

struct velocity {
    float dx;
    float dy;
};

// ...

int main() {
    entt::registry registry;
    // ..
        if(i % 2 == 0) { registry.emplace<velocity>(entity, i * .1f, i * .1f); }

In order for this to be valid, shouldn't there be a manual constructor that takes in 2 floats? How would emplace's forwarding of the args actually be utilized properly in this scenario to set properties of the velocity instance?

After seeing this, I started to think there is maybe some magic constructor in C++ structs that knows to take any args in a constructor call and assign them like... in order of their declaration in the struct? This seems quite nuts. I did some Googling to make sure and I couldn't find any such behavior, and running

new velocity(i *.1f, i *.1f)

will yield "no matching constructor" error.

documentation

All 6 comments

Eheh, yeah, no magic here. EnTT and specifically its default storage knows if a type is an aggregate or not and it constructs instances accordingly. It helps because most of the times my components are aggregates and I don't want to define a constructor for all of them.
So, the example just works because of this. The example you did is wrong instead. Roughly speaking, the default storage doesn't even invoke new, but let's suppose this is the case. The right form isn't this one though:

new velocity(i *.1f, i *.1f)

Instead, this is what it would be:

new velocity{i *.1f, i *.1f}

As you can see, it _just works_. :tm: 馃檪
Specifically, here is where the magic happens. Nothing special in fact, but still.

Hi @skypjack , I appreciate you taking the time to explain. I am still, however, a bit concerned about this from a dev accessibility standpoint - in this call:

registry.emplace<velocity>(entity, i * .1f, i * .1f);

It the case that arguments 2 and 3 (after entity) are intended to be the value of dx and dy. As per std::aggregate docs, it seems this is very possible:

#include <iostream>

int main() {
    struct Velocity
    {
        float dx;
        float dy;
    };

    Velocity vel{1.9f, 2.7f};

    std::cout << "DX: " << vel.dx << ", DY:" << vel.dy << std::endl;
    return 0;
}

// outputs DX: 1.9, DY:2.7

I think this is just somewhat unintuitive because I was under the impression that emplace would generate templates based on the constructors of the struct provided, but I think I see now that std::aggregate essentially autogenerates constructors for its adherents that allow you to specify arguments in sequence of declaration within the class/struct that emplace is calling.

This seems moreso like I just need to level up my knowledge of C++ than something entt should contend with, but I do wonder if maybe the example should specifically note that those structs are std::aggregates and that emplace is depending on that. Maybe even one of those structs could have a constructor in order to show consumers of the library an example that is more initially intuitive.

Again, I am not 100% certain if I am personally indicative of your average C++ developer, but I have read tens of thousands of pages of C++ books in my lifetime and this feature has never come up. I suspect there is a chance that you would need to be in some upper percentile of professional C++ developer to even know about this behavior, but it is possible I am just very much in the bottom percentile :)

I second making a more specific note in the documentation, or even just adding the extra constructor in the code sample for clarity's sake.

I will submit a PR for this and you folks can approve or modify if you agree/disagree :) it will in by EOD.

Thanks. I'll look into it tomorrow morning (it's midnight here at the moment). 馃檪

Upstream on doc, soon on master. Thanks for pointing this out. 馃憤

Was this page helpful?
0 / 5 - 0 ratings