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
- 注意,更换功能将具有相同的功能 表单作为模板一-还要注意常量/非常量 函数类型
- 调用可能具有非模板的模板函数时 替换函数或不同的模板参数函数在不使用模板参数的情况下调用它
- 无法根据退货类型进行更换。因此,如果您的类型 是唯一标识函数的,请将其作为参数放置
- 使用参数包替换函数时,最好使用具有相同参数包的替换函数
// 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