C++模板类成员模板函数构造实例报C2664编译错误
问题根因
编译报错由两个C++模板规则相关的问题共同导致:
- 注入类名解析歧义:在
C_SharedResource<T>的类作用域(包括成员函数体)内,未加限定的C_SharedResource名称会被编译器优先解析为当前实例C_SharedResource<T>的注入类名,而非通用类模板本身。此时名称后跟随的<T2>会被尝试解析为小于比较运算符,直接导致后续构造函数的重载匹配逻辑出错,错误匹配到接收const T&参数的构造重载。 - 嵌套类型实例不兼容:
S_AutoDestructionData被定义在C_SharedResource<T>类模板内部,该结构体会随每一个模板参数T生成独立的类型。也就是说C_SharedResource<T>::S_AutoDestructionData和C_SharedResource<T2>::S_AutoDestructionData是完全无关的两个类型,即便成员定义完全一致也无法隐式转换,无法作为合法参数传入C_SharedResource<T2>的构造函数。
修复方案
按以下两点修改即可解决编译错误:
- 将和模板参数
T无逻辑关联的S_AutoDestructionData结构体移动到C_SharedResource类模板外部定义,消除不同模板实例下的结构体类型差异。 - 在成员模板函数内构造其他模板参数实例的
C_SharedResource对象时,用::全局命名空间限定类名,绕开注入类名的查找规则,避免解析歧义。
修正后可正常编译的完整代码
#include <iostream> #include <memory> class C_Instance { public: virtual void some_func() {} }; // 将和模板参数无关的S_AutoDestructionData挪到类模板外定义 struct S_AutoDestructionData { bool m_autoDestroyAllInstances = false; bool m_transferAutoDestructionState = false; }; 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; 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; }
补充:如果不想把
S_AutoDestructionData挪到类外,也可以在类内通过using声明引入全局定义的同名结构体,本质上只要保证所有C_SharedResource实例使用同一个S_AutoDestructionData类型即可。
内容的提问来源于stack exchange,提问作者DEFAULT
相关产品推荐
相关产品推荐

