Compiler: MSVC (Visual Studio 2019)
On the latest master and the latest stable release 3.3.0.
Hi,
I searched for past issues and I couldn't find any references to that bug. I am not a metaprogramming god so I might be missing something obvious. This is something we were able to do. The function used to behave like assign:
reg.assign<C>(ent, a, b, c, ...)
reg.assign_or_replace<C>(ent, a, b, c, ...)
Trying to do this:
struct HitPoints
{
int amount;
};
```cpp
auto ent = reg.create();
reg.assign_or_replace
Will result in a compile error:
`tuple(853,15): error C2440: '<function-style-cast>': cannot convert from '_Ty' to '_Ty'`
_full error log at the bottom of the issue_
This workaround works:
```cpp
auto& hitPoints = reg.assign_or_replace<HitPoints>(ent);
hitPoints.amount = 50;
Full error log:
1>------ Build started: Project: tmp11, Configuration: Debug x64 ------
1>main.cpp
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(853,15): error C2440: '<function-style-cast>': cannot convert from '_Ty' to '_Ty'
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(853,15): error C2440: with
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(853,15): error C2440: [
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(853,15): error C2440: _Ty=int
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(853,15): error C2440: ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(853,15): error C2440: and
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(853,15): error C2440: [
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(853,15): error C2440: _Ty=HitPoints
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(853,15): error C2440: ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(852,49): message : No constructor could take the source type, or constructor overload resolution was ambiguous
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(860): message : see reference to function template instantiation '_Ty std::_Make_from_tuple_impl<_Ty,const std::tuple<int &&>,0>(_Tuple &&,std::integer_sequence<unsigned __int64,0>)' being compiled
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(860): message : with
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(860): message : [
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(860): message : _Ty=HitPoints,
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(860): message : _Tuple=const std::tuple<int &&>
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple(860): message : ]
entt\src\entt\entity\registry.hpp(715): message : see reference to function template instantiation '_Ty std::make_from_tuple<Component,const std::tuple<int &&>>(_Tuple &&)' being compiled
entt\src\entt\entity\registry.hpp(715): message : with
entt\src\entt\entity\registry.hpp(715): message : [
entt\src\entt\entity\registry.hpp(715): message : _Ty=HitPoints,
entt\src\entt\entity\registry.hpp(715): message : Component=HitPoints,
entt\src\entt\entity\registry.hpp(715): message : _Tuple=const std::tuple<int &&>
entt\src\entt\entity\registry.hpp(715): message : ]
entt\src\entt\entity\registry.hpp(101): message : see reference to function template instantiation 'void entt::basic_registry<entt::entity>::assign_or_replace::<lambda_9dda6bfca99c5b9ab1648c540feba5df>::operator ()<HitPoints&>(HitPoints &) const' being compiled
entt\src\entt\entity\registry.hpp(715): message : see reference to function template instantiation 'void entt::basic_registry<entt::entity>::pool_handler<Component>::replace<entt::basic_registry<entt::entity>::assign_or_replace::<lambda_9dda6bfca99c5b9ab1648c540feba5df>>(entt::basic_registry<entt::entity> &,const Entity,entt::basic_registry<Entity>::assign_or_replace::<lambda_9dda6bfca99c5b9ab1648c540feba5df> &&)' being compiled
entt\src\entt\entity\registry.hpp(715): message : with
entt\src\entt\entity\registry.hpp(715): message : [
entt\src\entt\entity\registry.hpp(715): message : Component=HitPoints,
entt\src\entt\entity\registry.hpp(715): message : Entity=entt::entity
entt\src\entt\entity\registry.hpp(715): message : ]
entt\src\entt\entity\registry.hpp(719): message : see reference to function template instantiation 'void entt::basic_registry<entt::entity>::pool_handler<Component>::replace<entt::basic_registry<entt::entity>::assign_or_replace::<lambda_9dda6bfca99c5b9ab1648c540feba5df>>(entt::basic_registry<entt::entity> &,const Entity,entt::basic_registry<Entity>::assign_or_replace::<lambda_9dda6bfca99c5b9ab1648c540feba5df> &&)' being compiled
entt\src\entt\entity\registry.hpp(719): message : with
entt\src\entt\entity\registry.hpp(719): message : [
entt\src\entt\entity\registry.hpp(719): message : Component=HitPoints,
entt\src\entt\entity\registry.hpp(719): message : Entity=entt::entity
entt\src\entt\entity\registry.hpp(719): message : ]
main.cpp(13): message : see reference to function template instantiation 'HitPoints &entt::basic_registry<entt::entity>::assign_or_replace<HitPoints,int>(const entt::entity,int &&)' being compiled
1>Done building project "tmp11.vcxproj" -- FAILED.
One more comment on this:
I think this function is used to be called accommodate. Here is one of the games I wrote (linked from your documentation) that relies on this feature:
https://github.com/Daivuk/tddod/blob/25ce0b0ebe1d52cc46ff7493f58c6cb2dae4970c/src/helpers/TowerHelpers.cpp#L100-L102
For your help, tracked down the commit that broke it using git bisect: https://github.com/skypjack/entt/commit/e7403d85516d07ce651708433e8f57134a85667f
hope this help
cannot convert from '_Ty' to '_Ty'
Best message ever though. :smile:
Thank you for reporting this. Gimme the time to look into it. I'll try to give you a feedback as soon as possible.
I'm a bit busy today, so it may happen that I won't be able to investigate this issue until tomorrow. I'm sorry.
Yup, error reporting on this is hard to read lol
No rush. I just noticed that after updating to latest. There's a workaround.
Also another note: The syntax with the functor also doesn't work it seems:
.assign_or_replace(ent, [](auto& hitPoints){...
No, this doesn't work, confirmed. It's only available for replace.
In this case, I decided to uniform the syntax with that of an assign since the intended action is to _assign_ the component to the entity rather than to _replace_ it.
It's a bit tricky to make the two work together without another function (like replace_or_assign), because you cannot really discern if the lambda is a callback to invoke or an argument to construct the component.
Wow, I've just realized that you found probably one of the few things that doesn't have a proper test.
Chapeau. Thank you very, very much for pointing this out. Good catch.
Good to hear, because I almost didn't report it. Thinking there was probably a reason for deprecating this behavior beyond my understanding.
edit: Also surprised I'm the first one to catch it. accommodate was one of my most used feature. Especially to mark entities as <Dead>.
Oh, it's std::make_from_tuple. It doesn't work with aggregates.
In your specific case, a proper constructor is enough to work around the issue:
struct HitPoints {
HitPoints(int v): amount{v} {}
int amount;
};
Again, good catch. Believe or not, there wasn't a test for this and I missed the issue.
May I ask you to check this with your tests?
template<typename Component, typename... Args>
decltype(auto) assign_or_replace(const entity_type entity, Args &&... args) {
ENTT_ASSERT(valid(entity));
auto &cpool = assure<Component>();
return cpool.has(entity)
? (cpool.replace(*this, entity, [&args...](auto &&component) { component = Component{std::forward<Args>(args)...}; }), cpool.get(entity))
: cpool.assign(*this, entity, std::forward<Args>(args)...);
}
It's a drop-in replacement for assign_or_replace. Since I'm not going to return the lambda, we can just capture things by reference and construct an instance of Component on the fly by forwarding them. There isn't the possibility for a dangling pointer and thus for UB here. std::forward_as_tuple and std::make_from_tuple were a bit overkilling probably.
Just tried, it works 馃憤
I've created a new release for this. See v3.3.1 for more details.
The changelog is already available. Thank you again for pointing this out.