I have a template class defined as so:
template<typename T> class C_SharedResource : public C_Instance
{
// ...
private:
std::shared_ptr<T> g_resource;
S_AutoDestructionData g_autoDestructionData{};
// ...
public:
C_SharedResource() {}
C_SharedResource(const T& in_resource, S_AutoDestructionData in_autoDestructionData = { false, false });
C_SharedResource(const std::shared_ptr<T>& in_resource, S_AutoDestructionData in_autoDestructionData = { false, false });
template<typename T2> C_SharedResource<T2> dynamic_cast_resource() const;
// ...
}
With the definition of dynamic_cast_resource being:
template<typename T>
template<typename T2>
C_SharedResource<T2> C_SharedResource<T>::dynamic_cast_resource() const
{
T2* tempResourcePtr = dynamic_cast<T2*>(g_resource.get());
if (tempResourcePtr == nullptr)
{
return C_SharedResource<T2>();
}
// This lines causes the compiler error.
C_SharedResource<T2> tempSharedResource(std::dynamic_pointer_cast<T2>(g_resource), g_autoDestructionData);
return tempSharedResource;
}
The idea behind the function is to down cast the stored shared pointer, and then return a newly constructed shared resource with the appropriate derived type.
An example of it being used:
// C_ITransformEntityComponent publicly inherits from C_IEntityComponent, which is also virtual.
std::shared_ptr<C_ITransformEntityComponent> transformComponent = std::make_shared<C_ITransformEntityComponent>();
C_SharedResource<C_IEntityComponent> sharedTC_1(transformComponent);
C_SharedResource<C_ITransformEntityComponent> sharedTC_2;
C_SharedResource<C_ITransformEntityComponent> sharedTC_3 = sharedTC_1.dynamic_cast_resource<C_ITransformEntityComponent>();
However the line:
C_SharedResource<T2> tempSharedResource(std::dynamic_pointer_cast<T2>(g_resource), g_autoDestructionData);
Fails to compile, with the error:
Error C2664 'C_SharedResource<C_ITransformEntityComponent>::C_SharedResource(const T &,C_SharedResource<T>::S_AutoDestructionData)': cannot convert argument 1 from 'std::shared_ptr<C_ITransformEntityComponent>' to 'const T &'
I am using Visual Studio 2022, with the C standard set to C 20.
Edit: Minimal reproducible example:
#include <iostream>
#include <memory>
class C_Instance
{
public:
virtual void some_func() {}
};
template<typename T> class C_SharedResource : public C_Instance
{
public:
struct S_AutoDestructionData
{
bool m_autoDestroyAllInstances = false;
bool m_transferAutoDestructionState = false;
};
private:
std::shared_ptr<T> g_resource;
S_AutoDestructionData g_autoDestructionData{};
public:
C_SharedResource() {}
C_SharedResource(const T& in_resource, S_AutoDestructionData in_autoDestructionData = { false, false });
C_SharedResource(const std::shared_ptr<T>& in_resource, S_AutoDestructionData in_autoDestructionData = { false, false });
template<typename T2> C_SharedResource<T2> dynamic_cast_resource() const;
void some_func() override {}
};
class C_IEntityComponent
{
public:
virtual void some_other_func() {}
};
class C_ITransformEntityComponent : public C_IEntityComponent
{
public:
void some_other_func() override {}
};
template<typename T>
template<typename T2>
C_SharedResource<T2> C_SharedResource<T>::dynamic_cast_resource() const
{
T2* tempResourcePtr = dynamic_cast<T2*>(g_resource.get());
if (tempResourcePtr == nullptr)
{
return C_SharedResource<T2>();
}
C_SharedResource<T2> tempSharedResource(std::dynamic_pointer_cast<T2>(g_resource), g_autoDestructionData);
return tempSharedResource;
}
int main()
{
std::shared_ptr<C_ITransformEntityComponent> transformComponent = std::make_shared<C_ITransformEntityComponent>();
C_SharedResource<C_IEntityComponent> sharedTC_1(transformComponent);
C_SharedResource<C_ITransformEntityComponent> sharedTC_2;
C_SharedResource<C_ITransformEntityComponent> sharedTC_3 = sharedTC_1.dynamic_cast_resource<C_ITransformEntityComponent>();
return 0;
}
CodePudding user response:
You get the compiler error because struct S_AutoDestructionData
is a nested type:
template<typename T> class C_SharedResource : public C_Instance
{
public:
struct S_AutoDestructionData
{
bool m_autoDestroyAllInstances = false;
bool m_transferAutoDestructionState = false;
};
// ...
C_SharedResource(const T& in_resource, S_AutoDestructionData in_autoDestructionData = { false, false });
// ^ C_SharedResource<T>::S_AutoDestructionData
C_SharedResource(const std::shared_ptr<T>& in_resource, S_AutoDestructionData in_autoDestructionData = { false, false });
// ^ C_SharedResource<T>::S_AutoDestructionData
// ...
};
So, in this line:
// T = C_IEntityComponent
// T2 = C_ITransformEntityComponent
C_SharedResource<T2> tempSharedResource(std::dynamic_pointer_cast<T2>(g_resource), g_autoDestructionData);
C_SharedResource<T2>
's constructor expects a C_SharedResource<T2>::S_AutoDestructionData
as the second argument; while you're passing a C_SharedResource<T>::S_AutoDestructionData
.
Those are not the same type.
If you pull struct S_AutoDestructionData
out from class C_SharedResource
:
struct S_AutoDestructionData
{
bool m_autoDestroyAllInstances = false;
bool m_transferAutoDestructionState = false;
};
template<typename T> class C_SharedResource : public C_Instance
{
public:
// ...
};
struct S_AutoDestructionData
wont be nested anymore and your code will compile.