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
C++11 为特定类型触发虚拟函数而不是具有可变参数的成员模板函数_C++11_Templates_Variadic Templates - Fatal编程技术网

C++11 为特定类型触发虚拟函数而不是具有可变参数的成员模板函数

C++11 为特定类型触发虚拟函数而不是具有可变参数的成员模板函数,c++11,templates,variadic-templates,C++11,Templates,Variadic Templates,我有一个模板成员函数,我想为大多数类型调用它,但对于某些特定类型,我需要调用虚拟成员函数 这种情况(请不要关注工厂设计,它只是用来提出C++问题,而不是因为工厂需要的设计): //工厂 阶级工厂 { //默认创建函数 模板 T*创建(参数和参数)常量 { 返回新的T(标准::转发(参数)…); } //处理类型A的创建 虚拟A*create(int i_i,const std::string&i_s)const=0; //处理类型C的创建 虚拟C*create(int i_i)const=0;

我有一个模板成员函数,我想为大多数类型调用它,但对于某些特定类型,我需要调用虚拟成员函数

这种情况(请不要关注工厂设计,它只是用来提出C++问题,而不是因为工厂需要的设计):

//工厂
阶级工厂
{
//默认创建函数
模板
T*创建(参数和参数)常量
{
返回新的T(标准::转发(参数)…);
}
//处理类型A的创建
虚拟A*create(int i_i,const std::string&i_s)const=0;
//处理类型C的创建
虚拟C*create(int i_i)const=0;
};
例如:

Factory* pFactory = new DerivedFactoryObject;
A* pA = pFactory->creat<A>(4,"Test");
Factory*pFactory=新的派生FactoryObject;
A*pA=P工厂->创建(4,“测试”);
但它总是调用模板函数,而不是A或C的虚拟函数

我尝试使用如下模板专门化:

    template<>
    template<typename... Args>
    A* create<A>(Args&&...parametes) const
    {
        return createA(std::forward<Args>(parametes)...);
    }

     virtual A* createA(int i_i, const std::string& i_s) const =0;
模板
模板
A*创建(参数和参数)常量
{
返回createA(std::forward(参数)…);
}
虚拟A*createA(int i_i,const std::string&i_s)const=0;
但实际上,不可能对函数进行部分专门化,事实上,编译失败了


那么我该怎么做呢?

我花了好几天的时间才弄明白怎么做,所以我很乐意在这里给出我的结论,作为一个教程,帮助其他人了解我们可以了解的细节。这是一个开放的修正和改进,这就是为什么我写在这里作为一个问题

为了说明所涉及的问题,我用一个小例子一步一步地解释这个主题。在本例中,我们希望使用工厂构建一个对象创建者,在这里我们可以使用不同类型的工厂来获得不同的对象创建方式

基本版本:

首先,让我们从我们工厂的基本版本开始

// forward decleration
class Creator;

// factory 
class Factory
{
public:
    Factory() = default;
    virtual ~Factory() = default;
private:
    // create is private to prevent using it, only class Creator can use it.
    template<typename T, typename... Args>
    T* create(Args&&...parametes) const
    {
        return new T(std::forward<Args>(parametes)...);
    }

    // allow only calss Creator to use factoy's create function
    friend class Creator;
};

// for having cleaner code
using FactorySPtr = std::shared_ptr<Factory>;
但这行不通

让我们检查一下

在接下来的运行中,我们使用FactoryEve类型构造了一个creator,以便在创建a和C时得到不同的处理

跟踪调用表明,所有创建都是使用TemplateFactory::create函数完成的,而不是替换函数

Creator creator(std::make_shared<FactoryEve>());

std::shared_ptr<A> spA = creator.create<A>(4, "test");                              // Bug -- created by template<typename T> T* Factory::create
std::shared_ptr<B> spB = creator.create<B>(std::vector<float>({0.1f,0.2f,0.3f}));   // Ok  -- created by template<typename T> T* Factory::create
std::shared_ptr<C> spC = creator.create<C>(67);                                     // Bug -- created by template<typename T> T* Factory::create
但我们不能,因为虚拟函数不能是模板

哈!似乎我们只是从一个问题到另一个问题

幸运的是,我们可以通过使用调用虚拟函数的模板替换函数轻松解决此问题,如下所示:

    template<>
    template<typename... Args>
    A* create<A>(Args&&...parametes) const
    {
        return createA(std::forward<Args>(parametes)...);
    }

     virtual A* createA(int i_i, const std::string& i_s) const =0;
(请注意,虚拟函数现在每个都有一个唯一的名称createA和createc)

//工厂
阶级工厂
{
公众:
Factory()=默认值;
virtual~Factory()=默认值;
私人:
//create是私有的以防止使用它,只有类创建者才能使用它。
//返回对象指针作为参数放置,以允许编译器找到正确的函数
模板
无效创建(T*&o\p,参数和参数)常量
{
o_p=新T(标准:正向(参数)…);
}
//功能替换
模板
void create(A*&o_p,Args&&…参数)常量
{
//调用创建
createA(o_p,std::forward(参数)…);
}
//C语言的函数替换
模板
无效创建(C*&o\p,参数和参数)常量
{
//调用创建C的虚函数
createC(o_p,std::forward(参数)…);
}
虚拟void createA(A*&o\u p,int i\u i,const std::string&i\u s)const
{
o_p=新的A(i_i,i_s);
}
虚空createC(C*&o\p,int i\u i)常量
{
o_p=新的C(i_i);
}
//仅允许calss创建者使用Factory的创建功能
好友类创建者;
};
通过这种方式,我们在使用相同的参数包(确保获得相同的表单)的同时替换了一个通用的create template函数,而且我们还有虚拟机制,允许不同的工厂类型用于不同的创建方法

现在它工作了

别忘了将FactoryEve中的函数名修改为createA和createC,现在如果运行,您将得到您想要的:

Creator creator(std::make_shared<FactoryEve>());

std::shared_ptr<A> spA = creator.create<A>(4, "test");                              // Ok  -- created by FactoryEve::createA
std::shared_ptr<B> spB = creator.create<B>(std::vector<float>({0.1f,0.2f,0.3f}));   // Ok  -- created by template<typename T> Factory::create
std::shared_ptr<C> spC = creator.create<C>(67);                                     // Ok  -- created by FactoryEve::createC
Creator-Creator(std::make_-shared());
std::shared_ptr spA=creator.create(4,“test”);//确定--由FactoryEve::createA创建
std::shared_ptr spB=creator.create(std::vector({0.1f,0.2f,0.3f}));//确定--由模板工厂创建::创建
std::shared_ptr spC=creator.create(67);//确定--由FactoryEve::createC创建
最后一句话:

对于使用虚拟函数用参数包替换模板成员函数,我们实际上不需要将它们用作替换,而是从不同的模板替换函数调用它们

Creator creator(std::make_shared<FactoryEve>());

std::shared_ptr<A> spA = creator.create<A>(4, "test");                              // Bug -- created by template<typename T> T* Factory::create
std::shared_ptr<B> spB = creator.create<B>(std::vector<float>({0.1f,0.2f,0.3f}));   // Ok  -- created by template<typename T> T* Factory::create
std::shared_ptr<C> spC = creator.create<C>(67);                                     // Bug -- created by template<typename T> T* Factory::create
  • 注意,更换功能将具有相同的功能 表单作为模板一-还要注意常量/非常量 函数类型
  • 调用可能具有非模板的模板函数时 替换函数或不同的模板参数函数在不使用模板参数的情况下调用它
  • 无法根据退货类型进行更换。因此,如果您的类型 是唯一标识函数的,请将其作为参数放置
  • 使用参数包替换函数时,最好使用具有相同参数包的替换函数

谢谢:)只要阅读开头的几行,你就会发现这是一本面向所有人的教程。您可以更正和改进。您不能重写函数模板。只能重写虚函数,而不能重写其他任何函数,并且只能在派生类中重写。你说的是重载,并无缘无故地称之为“覆盖”。非常感谢@n.“代词”m。你是对的,我是对的
// factory 
class Factory
{
public:
    Factory() = default;
    virtual ~Factory() = default;

private:
    // create is private to prevent using it, only class Creator can use it.
    template<typename T, typename... Args>
    T* create(Args&&...parametes) const
    {
        return new T(std::forward<Args>(parametes)...);
    }

    // function replacement for A
    virtual A* create(int i_i, const std::string& i_s) const
    {
        return new A(i_i,i_s);
    }
    
    // function replacement for C
    virtual C* create(int i_i) const
    {
        return new C(i_i);
    }

    // allow only calss Creator to use factoy's create function
    friend class Creator;
};
using FactorySPtr = std::shared_ptr<Factory>;
// eve factory 
class FactoryEve : public Factory
{
public:
    FactoryEve() = default;
    virtual ~FactoryEve() = default;

private:
    virtual A* create(int i_i, const std::string& i_s) const
    {
        A* p = new A(i_i, i_s);
        p->s += "_Hey!";
        return p;
    }

    virtual C* create(int i_i) const
    {
        C* p = new C(i_i);
        p->i += 5;
        return p;
    }
};
Creator creator(std::make_shared<FactoryEve>());

std::shared_ptr<A> spA = creator.create<A>(4, "test");                              // Bug -- created by template<typename T> T* Factory::create
std::shared_ptr<B> spB = creator.create<B>(std::vector<float>({0.1f,0.2f,0.3f}));   // Ok  -- created by template<typename T> T* Factory::create
std::shared_ptr<C> spC = creator.create<C>(67);                                     // Bug -- created by template<typename T> T* Factory::create
T* p = m_spFactory->create<T>(std::forward<Args>(parametes)...);
T* p = m_spFactory->create(std::forward<Args>(parametes)...);
// factory 
class Factory
{
public:
    Factory() = default;
    virtual ~Factory() = default;

private:
    // create is private to prevent using it, only class Creator can use it.
    // return object pointer is placed as a parameter to allow the compiler to find the correct function
    
    template<typename T, typename... Args>
    void create(T*& o_p, Args&&...parametes) const
    {
        o_p = new T(std::forward<Args>(parametes)...);
    }

    // function replacement for A
    virtual void create(A*& o_p, int i_i, const std::string& i_s) const
    {
        o_p = new A(i_i, i_s);
    }

    // function replacement for C
    virtual void  create(C*& o_p, int i_i) const
    {
        o_p = new C(i_i);
    }

    // allow only calss Creator to use factoy's create function
    friend class Creator;
};
class Creator
{
public:
    Creator(FactorySPtr  i_spFactory) : m_spFactory(i_spFactory) {}

    template<typename T, typename... Args>
    std::shared_ptr<T> create(Args&&...parametes) const
    {
        T* p;
        m_spFactory->create(p, std::forward<Args>(parametes)...);
        return std::shared_ptr<T>(p);
    }   
private:
    FactorySPtr  m_spFactory;
};
Creator creator(std::make_shared<FactoryEve>());

std::shared_ptr<A> spA = creator.create<A>(4, "test");                              // Bug -- created by template<typename T> Factory::create 
std::shared_ptr<B> spB = creator.create<B>(std::vector<float>({0.1f,0.2f,0.3f}));   // Ok  -- created by template<typename T> Factory::create
std::shared_ptr<C> spC = creator.create<C>(67);                                     // Ok  -- created by FactoryEve::create(C*& o_p, int i_i)
    // function replacement for A
    template<typename... Args>
    virtual void create(A*& o_p, Args&&...parametes) const
    {
        o_p = new A(i_i, i_s);
    }
// factory 
class Factory
{
public:
    Factory() = default;
    virtual ~Factory() = default;

private:
    // create is private to prevent using it, only class Creator can use it.
    // return object pointer is placed as a parameter to allow the compiler to find the correct function
    
    template<typename T, typename... Args>
    void create(T*& o_p, Args&&...parametes) const
    {
        o_p = new T(std::forward<Args>(parametes)...);
    }

    // function replacement for A
    template<typename... Args>
    void create(A*& o_p, Args&&...parametes) const
    {
        // calling virtual function which create A 
        createA(o_p, std::forward<Args>(parametes)...);
    }

    // function replacement for C
    template<typename... Args>
    void create(C*& o_p, Args&&...parametes) const
    {
        // calling virtual function which create C 
        createC(o_p, std::forward<Args>(parametes)...);
    }

    virtual void createA(A*& o_p, int i_i, const std::string& i_s) const
    {
        o_p = new A(i_i, i_s);
    }

    virtual void  createC(C*& o_p, int i_i) const
    {
        o_p = new C(i_i);
    }

    // allow only calss Creator to use factoy's create function
    friend class Creator;
};
Creator creator(std::make_shared<FactoryEve>());

std::shared_ptr<A> spA = creator.create<A>(4, "test");                              // Ok  -- created by FactoryEve::createA
std::shared_ptr<B> spB = creator.create<B>(std::vector<float>({0.1f,0.2f,0.3f}));   // Ok  -- created by template<typename T> Factory::create
std::shared_ptr<C> spC = creator.create<C>(67);                                     // Ok  -- created by FactoryEve::createC