Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/31.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;返回多个类型作为引用_C++_Templates_Reference - Fatal编程技术网

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";
}