"Cannot convert from 'A' to 'B&' - c++

I'm building an Entity-Component system using template metaprogramming. I keep getting either Cannot convert from [base type] to [type user requested]& or Cannot convert NullComponent to [type user requested]& errors:
class Entity {
public:
Entity() = default;
~Entity() = default;
template<typename C, typename... Args>
void AddComponent(Args&&... args);
template<typename C>
C& GetComponent();
protected:
private:
//...add/get helper methods here...
unsigned int _id;
std::vector<std::unique_ptr<IComponent>> _components;
};
template<typename C>
C& Entity::GetComponent() {
for(auto c : _components) {
if(std::is_base_of<a2de::IComponent&, C&>().value && std::is_same<decltype(c), C&>().value) {
return *c; //<-- error here
}
}
return NullComponent(); //<-- and here
}
EDIT
These options seem to work for now.
template<typename C>
const C& Entity::GetComponent() const {
for(auto& uc : _components) {
auto* c = dynamic_cast<C*>(uc.get());
if(c && std::is_base_of<a2de::IComponent&, C&>().value && std::is_same<decltype(c), C&>().value) {
return *c;
}
}
throw std::runtime_error(std::string("Component not available."));
}
OR
class Entity {
public:
//same as before...
protected:
private:
//same as before...
a2de::NullComponent _null_component;
};
template<typename C>
const C& Entity::GetComponent() const {
for(auto& uc : _components) {
auto* c = dynamic_cast<C*>(uc.get());
if(c && std::is_base_of<a2de::IComponent&, C&>().value && std::is_same<decltype(c), C&>().value) {
return *c;
}
}
return _null_component;
}

At least three things:
In GetComponent() you iterate over unique_ptr elements and compare their type (always std::unique_ptr<IComponent>) with something else in the std::is_same. You probably don't want that.
You are returning a reference to a temporary in the final return, it seems.
return *c needs a dynamic_cast unless C == IComponent.
EDIT
Also:
std::is_base_of makes no sense with references. Even with class NullComponent : IComponent {};, you would still get std::is_base_of<IComponent&, NullComponent&>::value == false.
And you do not check for nullptr
In the end, it seems to me that you should replace your for loop with
for(auto& component : _components) {
auto* c = dynamic_cast<C*>(component.get());
if (c)
{
return *c;
}
}

At a high level, from what I can figure out, the return type cannot be used to define the template type. The parameter list can be used to define the template type.
So, for example, this might work -
template<typename C>
void Entity::GetComponent(C *obj) {
for(auto c : _components) {
if(std::is_base_of<a2de::IComponent&, C&>().value && std::is_same<decltype(c), C&>().value) {
obj = c; //<-- error here
return;
}
}
obj = NULL;
return; //<-- and here
}
Hope this helps.

Related

Common interface with a wrapper around std::variant or unions

This question is related to Enforcing a common interface with std::variant without inheritance.
The difference between that question and this one, is that I wouldn't mind inheritance, I am simply looking for the following structs/classes...
struct Parent { virtual int get() = 0; };
struct A : public Parent { int get() { return 1; } };
struct B : public Parent { int get() { return 2; } };
struct C : public Parent { int get() { return 3; } };
... to be AUTOMATICALLY "assembled" into a template:
template<typename PARENT, typename... TYPES>
struct Multi
{
// magic happens here
}
// The type would accept assignment just like an std::variant would...
Multi<Parent, A, B, C> multiA = A();
Multi<Parent, A, B, C> multiB = B();
Multi<Parent, A, B, C> multiC = C();
// And it would also be able to handle virtual dispatch as if it were a Parent*
Multi<Parent, A, B, C> multiB = B();
multiB.get(); // returns 2
Is this possible? If so, how? I would like to avoid working with handling pointers, as the use of std::variant/unions is intended to make memory contiguous.
You can't automagically set this up to allow multiB.get(), but you can allow multiB->get() or (*multiB).get() and even implicit conversion, by providing operator overloads:
template<typename Base, typename... Types>
struct Multi : std::variant<Types...>
{
using std::variant<Types...>::variant;
operator Base&() { return getref<Base>(*this); }
Base& operator*() { return static_cast<Base&>(*this); }
Base* operator->() { return &static_cast<Base&>(*this); }
operator const Base&() const { return getref<const Base>(*this); }
const Base& operator*() const { return static_cast<const Base&>(*this); }
const Base* operator->() const { return &static_cast<const Base&>(*this); }
private:
template<typename T, typename M>
static T& getref(M& m) {
return std::visit([](auto&& x) -> T& { return x; }, m);
}
};
You've probably encountered this kind of thing before when using iterators from the standard library.
Example:
int main()
{
Multi<Parent, A, B, C> multiA = A();
Multi<Parent, A, B, C> multiB = B();
Multi<Parent, A, B, C> multiC = C();
// Dereference
std::cout << (*multiA).get();
std::cout << (*multiB).get();
std::cout << (*multiC).get();
// Indirection
std::cout << multiA->get();
std::cout << multiB->get();
std::cout << multiC->get();
// Implicit conversion
auto fn = [](Parent& p) { std::cout << p.get(); };
fn(multiA);
fn(multiB);
fn(multiC);
}
Output:
123123123

Type punning issue: Can't reinterpret_cast member function pointer of class which derives from multiple classes into dummy member function pointer

Iam new in C++ and do not know what am I doing so please help.
The issue is, when Iam trying to do this in Visual Studio 2022, it does not compile:
I replaced std::function with this in my codebase. It supposed to be used as a delegate in event system.
TFunction.h:
namespace t3d
{
template<typename T> class TFunction;
template<typename Return_T, typename... Args_T>
class TFunction<Return_T(Args_T...)>
{
public:
// Aliases:
template<class C>
using CallbackMember_T = Return_T(C::*)(Args_T...);
using CallbackStatic_T = Return_T(*)(Args_T...);
// Constructors:
TFunction()
: CallbackMember (nullptr)
, FunctionPointers { &TFunction::CallMember, &TFunction::CallStatic }
, CallbackStatic (nullptr)
, Instance (nullptr)
, Index (0)
{
}
template<class C>
TFunction(C* Instance, CallbackMember_T<C> Callback)
: CallbackMember (reinterpret_cast<CallbackMember_T<FInstance>>(Callback))
, FunctionPointers { &TFunction::CallMember, &TFunction::CallStatic }
, CallbackStatic (nullptr)
, Instance (reinterpret_cast<FInstance*>(Instance))
, Index (0)
{
}
TFunction(CallbackStatic_T Callback)
: CallbackMember (nullptr)
, FunctionPointers { &TFunction::CallMember , &TFunction::CallStatic }
, CallbackStatic (Callback)
, Instance (nullptr)
, Index (1)
{
}
// Functions:
template<class C>
constexpr void Bind(C* Instance, CallbackMember_T<C> Callback) noexcept
{
this->Instance = reinterpret_cast<FInstance*>(Instance);
this->CallbackMember = reinterpret_cast<CallbackMember_T<FInstance>>(Callback);
this->CallbackStatic = nullptr;
this->Index = 0;
}
constexpr void Bind(CallbackStatic_T Callback) noexcept
{
this->Instance = nullptr;
this->CallbackMember = nullptr;
this->CallbackStatic = Callback;
this->Index = 1;
}
constexpr Return_T Invoke(Args_T... Args) const
{
return (this->*FunctionPointers[Index])(std::forward<Args_T>(Args)...);
}
template<class C>
constexpr bool8 IsEqual(CallbackMember_T<C> Callback) const
{
return reinterpret_cast<CallbackMember_T<C>>(CallbackMember) == Callback;
}
constexpr bool8 IsEqual(CallbackStatic_T Callback) const noexcept
{
return CallbackStatic == Callback;
}
constexpr bool8 IsEmpty() const noexcept
{
return (Instance == nullptr) && (CallbackMember == nullptr) && (CallbackStatic == nullptr);
}
// Operators:
explicit operator bool () const noexcept
{
return (Instance && CallbackMember) || CallbackStatic;
}
constexpr bool8 operator == (const TFunction& Right) const noexcept
{
return (Instance == Right.Instance) && (CallbackMember == Right.CallbackMember) && (CallbackStatic == Right.CallbackStatic);
}
constexpr bool8 operator != (const TFunction& Right) const noexcept
{
return (Instance != Right.Instance) || (CallbackMember != Right.CallbackMember) || (CallbackStatic != Right.CallbackStatic);
}
private:
using CallbackInternal_T = Return_T(TFunction::*)(Args_T...) const;
// Private Functions:
Return_T CallMember(Args_T... Args) const
{
return (Instance->*CallbackMember)(std::forward<Args_T>(Args)...);
}
Return_T CallStatic(Args_T... Args) const
{
return (*CallbackStatic)(std::forward<Args_T>(Args)...);
}
// Variables:
class FInstance {};
CallbackMember_T<FInstance> CallbackMember;
CallbackInternal_T FunctionPointers[2];
CallbackStatic_T CallbackStatic;
FInstance* Instance;
uint64 Index;
};
}
Main.cpp:
Here am I testing TFunction with this exact code:
struct FData
{
int A;
int B;
};
struct FResult
{
bool Success;
};
class FBase1
{
public:
virtual FResult Function1(FData Data)
{
return FResult{ true };
}
};
class FBase2
{
public:
virtual FResult Function2(FData Data)
{
return FResult{ true };
}
};
class FDerived : public FBase1, public FBase2
{
public:
FResult Function1(FData Data) override
{
return FResult{ true };
}
FResult Function2(FData Data) override
{
return FResult{ true };
}
FResult Function3(FData Data)
{
return FResult{ true };
}
};
FResult FunctionGlobal(FData Data)
{
return FResult{ true };
}
t3d::int32 main()
{
FDerived Derived;
t3d::TFunction<FResult(FData)> TestFunction;
TestFunction.Bind(&Derived, &FDerived::Function1); // Error C2440
TestFunction.Bind(&Derived, &FDerived::Function2); // Error C2440
TestFunction.Bind(&Derived, &FDerived::Function3); // Error C2440
return 0;
}
Error says: 'reinterpret_cast': cannot convert from 'Return_T (__cdecl FDerived::* )(FData)' to 'Return_T (__cdecl t3d::TFunction<FResult (FData)>::FInstance::* )(FData)'
Any ideas?
Edited: Binding works fine with nested inheritance or with no inheritance, but not with inheritance from multiple classes.
Thanks guys for the participation, i found the answer in this thread:
Pointers to members representations
The issue was - member function pointers can have different representations because of the differences in the underlying structs and different sizes.
This is why they are not always can be reinterpreted as a different member function pointers. It is actually a Microsoft specific feature and can be turned off
by using /vmg, or as follows:
#if _WIN64
#pragma pointers_to_members( full_generality, multiple_inheritance )
#endif
where multiple_inheritance corresponds to the biggest representation.
And it turned out that "multiple_inheritance" is actually a C++ standard representation.

c++ 11 segmentation fault (core dumped),but c++ 17 not

class all {
public:
template <typename T>
all(T&& t)
: data_ptr(new derived<T>(std::forward<T>(t))) {
}
all()
: data_ptr(nullptr) {}
all(const all& o)
: data_ptr(o.clone()) {}
all(const all&& o)
: data_ptr(o.clone()) {}
all& operator=(const all& o) {
auto n = o.clone();
if (data_ptr != nullptr) {
delete data_ptr;
}
data_ptr = n;
return *this;
}
all& operator=(all&& a)
{
if (data_ptr == a.data_ptr)
return *this;
swap(data_ptr, a.data_ptr);
return *this;
}
~all() {
if (data_ptr != nullptr) {
delete data_ptr;
}
}
template <typename U>
bool is() const {
auto ret = dynamic_cast<derived<U>*>(data_ptr);
return ret != nullptr;
}
template<typename U> U& as(){
auto ret = dynamic_cast<derived<U>*>(data_ptr);
if (ret==nullptr){
throw std::runtime_error("type dynamic_cast error");
}
return ret->value;
}
template<typename U>operator U(){
return as<U>();
}
private:
struct base {
virtual base* clone() = 0;
virtual ~base(){};
};
template <typename T>
struct derived : public base {
template <typename U>
derived(U&& v)
: value(std::forward<U>(v)) {
}
T value;
base* clone() {
return new derived<T>(value);
}
};
base* data_ptr;
base* clone() const {
if (data_ptr == nullptr) {
return nullptr;
} else {
return data_ptr->clone();
}
}
};
cmake compile options:
set (CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0 ")
test cases as follows:
int main(int argc, char const* argv[]) {
all at = 12;
cout << at.is<int>() << endl;
cout<<at.as<int>()<<endl;
cout<<int(at)<<endl;
return 0;
}
c++11,17 both compile successful,but c++ 11 throw segmentation fault when run ,c++17 run successful,why? i'm so frustrated,can someone help me?
Here is Complete Reproducible Example (not minimal).
all at = 12;
It seems that the conversion sequence is this:
A temporary object is constructed from the right hand expression, using the constructor all::all<int>(int&&).
That temporary object is used to initialise at.
Since the temporary all is non-const, the template constructor is a better match than all(const all&&).
Hence, all::all<all>(all&&) is invoked. This initialises a all::derived<all>::derived which has an all member that is initialised using all::all<all>(all&&) (because that is again, a better match than all::all(const all&&)), which invokes all::all(const all&&) which initialises all::derived<all>::derived which invokes all::all(const all&&) ... can you spot the pattern? The recursion never ends. You eventually get a stack overflow.
In C++17 at is initialised directly from the initialiser without involving a temporary object, so there is no stack overflow.
A simple fix is to add a move constructor:
all(all&& o) : data_ptr{std::exchange(o.data_ptr, nullptr)} {}
P.S. Avoid the use of bare owning pointers such as data_ptr. Use smart pointers such as std::unique_ptr instead.

Lambda that uses dynamic cast

Let's suppose that we have 3 classes:
class A
{
public:
int a;
virtual ~A() = default;
};
class B : public A
{
public:
int b;
};
class C : public A
{
public:
int c;
};
And a vector that contains polymorphic objects derived from A
std::vector<A*> objects;
I want to have a template method, that will return me an object from vector of type gived in template, if that object exists, but I don't know how to write it..
This not work:
template<typename ComponentType>
ComponentType * GetComponent()
{
bool pred = std::find_if(objects.begin(), objects.end(),
[=](A * obj)
{
return
dynamic_cast<ComponentType*>(obj) != nullptr;
});
return pred != objects.end();
}
I know that it could be done with that code:
template<typename ComponentType>
ComponentType * GetComponent()
{
for (item : objects)
{
auto casted = dynamic_cast<ComponentType*>(item);
if (casted)
return casted;
}
return nullptr;
}
But I want to use lambda.
It does not work at least because std::find_if returns an iterator, not a bool.
You might change your solution to fix it and return either a pointer to the element or nullptr if there is no such element:
template<typename ComponentType>
ComponentType * GetComponent()
{
auto it = std::find_if(objects.begin(), objects.end(),
[](A * obj)
{
return dynamic_cast<ComponentType*>(obj) != nullptr;
});
return it != objects.end()
? dynamic_cast<ComponentType*>(*it)
: nullptr;
}
Note, that it is better to avoid dynamic_cast at all if it is possible. For example, you might add a virtual method to A class which identifies an object somehow, then override it in B and C and use to find a requested object.

one to one association

What is the best way to represent one-to-one object association in C++? It should be as automatic and transparent as possible meaning, that when one end is set or reset, the other end will be updated. Probably a pointer-like interface would be ideal:
template<typename AssociatedType>
class OneToOne{
void Associate(AssociatedType &);
AssociatedType &operator* ();
AssociatedType *operator->();
}
Is there any better way to do it or is there any complete implementation?
EDIT:
Desired behavior:
struct A{
void Associate(struct B &);
B &GetAssociated();
};
struct B{
void Associate(A &);
A &GetAssociated();
};
A a, a2;
B b;
a.Associate(b);
// now b.GetAssociated() should return reference to a
b.Associate(a2);
// now b.GetAssociated() should return reference to a2 and
// a2.GetAssociated() should return reference to b
// a.GetAssociated() should signal an error
Untested, but you could use a simple decorator
template <typename A1, typename A2>
class Association
{
public:
void associate(A2& ref)
{
if (_ref && &(*_ref) == &ref) return; // no need to do anything
// update the references
if (_ref) _ref->reset_association();
// save this side
_ref = ref;
ref.associate(static_cast<A1&>(*this));
}
void reset_association() { _ref = boost::none_t(); }
boost::optional<A2&> get_association() { return _ref; }
private:
boost::optional<A2&> _ref;
};
now:
struct B;
struct A : public Association<A, B> {
};
struct B : public Association<B, A> {
};
now these operations should be handled correctly.
A a, a2;
B b;
a.associate(b);
b.associate(a2);
NOTES: I use boost::optional to hold a reference rather than pointer, there is nothing stopping you from using pointers directly. The construct you are after I don't think exists by default in C++, which is why you need something like the above to get it to work...
Here is one class that can represent a bi-directional one-to-one relation:
template <class A, class B>
class OneToOne {
OneToOne<A,B>* a;
OneToOne<A,B>* b;
protected:
OneToOne(A* self) : a(self), b(0) {}
OneToOne(B* self) : a(0), b(self) {}
public:
void associateWith(OneToOne<A,B>& other) {
breakAssociation();
other.breakAssociation();
if (a == this) {
if (b != &other) {
breakAssociation();
other.associateWith(*this);
b = &other;
}
}
else if (b == this) {
if (a != &other) {
breakAssociation();
other.associateWith(*this);
a = &other;
}
}
}
A* getAssociatedObject(B* self) { return static_cast<A*>(a); }
B* getAssociatedObject(A* self) { return static_cast<B*>(b); }
void breakAssociation() {
if (a == this) {
if (b != 0) {
OneToOne<A,B>* temp = b;
b = 0;
temp->breakAssociation();
}
}
else if (b == this) {
if (a != 0) {
OneToOne<A,B>* temp = a;
a = 0;
temp->breakAssociation();
}
}
}
private:
OneToOne(const OneToOne&); // =delete;
OneToOne& operator=(const OneToOne&); // =delete;
};
Perhaps check out boost::bimap, a bidirectional maps library for C++.