C++ C++;返回多个类型作为引用
好的,我正在尝试设置一个模板方法,它根据参数请求返回一个未确定类型的引用。一切看起来都很好,但它一直告诉我,当我调用它时,所提供模板方法的重载方法不存在。代码如下所示:C++ C++;返回多个类型作为引用,c++,templates,reference,C++,Templates,Reference,好的,我正在尝试设置一个模板方法,它根据参数请求返回一个未确定类型的引用。一切看起来都很好,但它一直告诉我,当我调用它时,所提供模板方法的重载方法不存在。代码如下所示: class IObj { public: int id; } class ObjOne : public IObj {} class ObjTwo : public IObj {} class ObjThree : public IObj {} enum ObjectTypes { O1Type,
class IObj {
public:
int id;
}
class ObjOne : public IObj {}
class ObjTwo : public IObj {}
class ObjThree : public IObj {}
enum ObjectTypes {
O1Type,
O2Type,
O3Type
}
class ObjManager {
public:
std::vector< std::unique_ptr<ObjOne> > O1Holder;
std::vector< std::unique_ptr<ObjTwo> > O2Holder;
std::vector< std::unique_ptr<ObjThree> > O3Holder;
ObjManager() {}
template <class T>
T& GetObject(int oID, ObjectTypes oType) {
if(oType == ObjectTypes::O1Type) {
for(int i = 0; i < O1Holder.size(); i++) {
if(O1Holder[i]->id == oID) {
return *O1Holder[i];
}
}
}
else if(oType == ObjectTypes::O2Type) {
for(int i = 0; i < O2Holder.size(); i++) {
if(O2Holder[i]->id == oID) {
return *O2Holder[i];
}
}
}
else if(oType == ObjectTypes::O3Type) {
for(int i = 0; i < O3Holder.size(); i++) {
if(O3Holder[i]->id == oID) {
return *O3Holder[i];
}
}
}
}
}
int main() {
std::unique_ptr<ObjManager> oManager(new ObjManager());
ObjOne& a = oManager->GetObject(0, ObjectTypes::O1Type);
return 0;
}
类IObj{
公众:
int-id;
}
类对象:公共IObj{}
类ObjTwo:public IObj{}
类对象三:公共IObj{}
枚举对象类型{
O1类型,
O2Type,
O3型
}
类对象管理器{
公众:
std::vectorO1Holder;
std::vectorO2Holder;
std::vectorO3Holder;
ObjManager(){}
模板
T&GetObject(int-oID,ObjectTypes-oType){
if(oType==ObjectTypes::O1Type){
对于(int i=0;iid==oID){
申报表*O1持有人[i];
}
}
}
else if(oType==ObjectTypes::O2Type){
对于(inti=0;iid==oID){
返回*O2Holder[i];
}
}
}
else if(oType==ObjectTypes::O3Type){
对于(int i=0;iid==oID){
返回*O3Holder[i];
}
}
}
}
}
int main(){
std::unique_ptr oManager(新的ObjManager());
ObjOne&a=oManager->GetObject(0,ObjectTypes::O1Type);
返回0;
}
一切都很好,如果我返回向量中存储的对象的特定类型,我可以创建一个方法来返回对该对象的引用,但是我试图减少生成许多函数以返回每个不同类型的冗余。所以我想创建一个模板化方法,根据我请求的类型返回一个对象类型
它没有给我任何错误,它只是在表达式oManager->GetObject中的->下划线,并告诉我模板方法调用没有重载方法。具体来说,它声明“没有函数模板'ObjManager::GetObject'的实例与参数列表匹配,参数类型为(int,ObjectTypes)”,即使我将整数和ObjectTypes::传递到函数的参数列表中。我已经到处寻找这个问题的答案,但没有找到类似的情况来借鉴经验
编辑:对不起,我应该指定这是大量向量列表的前身,为了简单起见,我只放了3个。这就是为什么我试图创建一个可以处理不同类型返回的函数,这样我就不必为我创建的每个向量创建一个返回函数。返回对指定类型的引用的目的是因为每个派生类型都有唯一的数据,而这些数据不在基类中,所以我正在提取对象进行编辑。正如@tobi303所评论的,您应该在GetObject类中明确使用模板参数T。然后,您实际上可以避免重复自己,因为编译器将为您生成重复了3次的代码
template <class T>
T& GetObject(int oID) {
for(int i = 0; i < OHolder<T>.size(); i++) {
if(OHolder<T>[i]->id == oID) {
return *OHolder<T>[i];
}
}
模板
获取对象(int-oID)(&GetObject){
对于(int i=0;iid==oID){
返回*OHolder[i];
}
}
虽然您也必须定义OHolder模板函数。但不可能根据运行时信息(例如您的参数)更改函数的返回类型,因为编译器显然不知道这些返回类型 如果您将始终在编译时知道要选择的对象类型,则可以使用以下技巧: 步骤1:将枚举转换为两个空结构:
struct O1Type {};
struct O2Type {};
struct O3Type {};
步骤2:不要使用否则如果使用s,请使用函数重载:
ObjOne& GetObject(int oID, O1Type) {/* TODO*/}
ObjTwo& GetObject(int oID, O2Type) {/* TODO*/}
ObjThree& GetObject(int oID, O3Type) {/* TODO*/}
您现在可以使用
ObjOne& a = oManager->GetObject(0, O1Type());
(或者,更好的是auto&a=oManager->GetObject(0,O1Type());
)根本原因
模板参数类型推断不能仅基于函数的返回类型
在通往解决方案的路上
因此,您可以添加一个伪函数参数来传输类型信息:
template <class T>
T& GetObject(int oID, ObjectTypes oType, T&x) {
...
}
然后可以推断模板类型
但这并不能解决您的问题。这种类型推断是在编译时进行的,因此函数的所有可能返回都应该返回相同的类型(或可以转换为它的类型)
您的代码并非如此,这将导致其他编译错误(请参阅)
解决方案
唯一可行的解决方案是确定要返回的公分母。将函数设为非模板函数,返回IObj&
:
IObj& GetObject(int oID, ObjectTypes oType) {
...
}
然后,您还应该将返回对象作为多态对象进行管理。由于返回是通过引用进行的,因此这很好(即不发生切片)。返回的引用将真正引用返回的对象,无论其派生类型如何。但您必须重新设计多态性的调用代码:
IObj& a = oManager->GetObject(0, ObjectTypes::O1Type);
但这有点笨拙,因为您在枚举中指明了所需的类型,但最后引用了一个无法轻松处理的父对象
结论
正如您在函数中指出的预期返回类型,您最好使用Yussuf的rexcellent答案中的解决方案,但要应用类型推断的伪参数技术。您似乎试图同时使用运行时多态性和编译时(模板)多态性。它不是这样工作的。不能从同一个方法返回多个类型。
您可能想做的是定义一个像@yussuf这样的方法,或者完全开始使用运行时多态性——在这种情况下,您可以这样做
IObj& a = oManager->GetObject(0, ObjectTypes::O1Type);
#include <vector>
#include <memory>
class Base {
public:
int ID;
Base(int id) { ID = id; }
}
class A : public Base {
public:
int X;
A(int id) : Base(id) {}
}
class B : public Base {
public:
int Y;
B(int id) : Base(id) {}
}
template <class T>
class MyContainer {
private:
std::vector<std::unique_ptr<T>> internalContainer;
public:
MyContainer() {}
~MyContainer() {}
void CreateItem(int id) {
std::unique_ptr<T> newItem(new T(id));
internalContainer.push_back(std::move(newItem));
}
T& GetItem(int id) {
for(std::vector<std::unique_ptr<T>>::iterator it = internalContainer.begin(); it!= internalContainer.end(); ++it) {
if((*it)->ID == id) {
return **it;
}
}
}
}
int main() {
MyContainer<A> AList;
MyContainer<B> BList;
AList.CreateItem(0);
BList.CreateItem(0);
A& AOne = AList.GetItem(0);
B& BOne = BList.GetItem(0);
AOne.X = 10;
BOne.Y = 20;
std::cout << std::to_string(AOne.X) << "\n";
std::cout << std::to_string(BOne.Y) << "\n";
}