It's basically a ZST, so only when you want to know whether it exists for an entity or not, no data.
The easiest way to understand entt::tag is probably to look at its definition which I'll repeat below (ENTT_ID_TYPE is a macro that expands to std::uint32_t).
template <std::uint32_t Value>
using tag = std::integral_constant<std::uint32_t, Value>;
Tags are used in ECS when you want to label things. They're an alternative to enums with some performance benefits (though that depends on how you use them). The example from the docs is repeated below:
registry.assign<entt::tag<"enemy"_hs>>(entity);
This is an alternative to defining the tag yourself.
struct Enemy {};
registry.assign<Enemy>(entity);
If you wanted to move all the enemies to the right then you could do this:
// One or the other
auto view = registry.view<Position, entt::tag<"enemy"_hs>>();
auto view = registry.view<Position, Enemy>();
// using less instead of each to omit empty components
view.less([](auto pos) {
pos.x += 10;
});
This is much faster than if you used an enum.
I personally prefer to define empty types rather than use entt::tag because if you misspell the name of a struct, the compiler has your back. If you write entt::tag<"enemy"_hs> in one place and entt::tag<"Enemy"_hs> somewhere else then it might not always be obvious that something has gone wrong. Also, I find that entt::tag is a bit more verbose than writing the name of a struct.
Yeah, it's just a misplaced shortcut for std::integral_constant where the integral type is ENTT_ID_TYPE.
I'm moving it under core/type_traits.hpp because actually it's not strictly related to hashed strings. For example, you can easily use it with enums.
Nothing special though.
Ok, that makes sense. I think, IDK I'll think on it though. :)
edit: Thank you all for the responses. 馃憤