对于特定类型,使用可变参数触发虚函数而不是成员模板函数
Firing virtual function instead of member template function with variadic arguments, for specific types
我有一个模板成员函数,我想为大多数类型调用它,但对于某些特定类型,我需要调用虚拟成员函数。
类似这样的东西(请不要关注“工厂设计”,它只是为了提出 c++ 问题,而不是因为这是工厂必然需要的设计):
// factory
class Factory
{
// default create function
template<typename T, typename... Args>
T* create(Args&&...parametes) const
{
return new T(std::forward<Args>(parametes)...);
}
// Handling creation for type A
virtual A* create(int i_i, const std::string& i_s) const =0;
// Handling creation for type C
virtual C* create(int i_i) const = 0;
};
使用例如:
Factory* pFactory = new DerivedFactoryObject;
A* pA = pFactory->creat<A>(4,"Test");
但它总是调用模板函数而不是 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;
但是实际上不可能对函数进行偏特化,确实编译失败了。
那我该怎么做呢?
我花了好几天的时间才弄清楚如何去做,所以我很乐意在这里给出我的结论作为帮助其他人理解我们可能遇到的细节的教程。它对更正和改进开放,这就是为什么我把它写在这里作为一个问题。
为了说明所涉及的问题,我用一个小例子逐步解释了这个主题。在这个例子中,我们希望使用工厂构建一个对象创建器,在这里我们可以使用不同类型的工厂来获得不同的对象创建方式。
基本版:
首先,让我们从工厂的基本版本开始。
// 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>;
这个工厂可以使用它的模板函数 create 创建不同类型的对象,它是私有的,只有 Creator 对象可以使用它 - 这就是我们声明 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<T>(std::forward<Args>(parametes)...);
return std::shared_ptr<T>(p);
}
private:
FactorySPtr m_spFactory;
};
构造时,它存储将用于创建对象的工厂。
为了展示它是如何使用的,假设我们有以下对象 A、B 和 C:
struct A
{
A(int i_i, const std::string& i_s) : i(i_i), s(i_s) {}
int i = 0;
std::string s;
};
struct B
{
B(const std::vector<float>& i_v) : v(i_v) {}
std::vector<float> v;
};
struct C
{
C(int i_i) : i(i_i) {}
int i = 0;
};
那么我们就可以使用creator如下:
Creator creator(std::make_shared<Factory>());
std::shared_ptr<A> spA = creator.create<A>(4, "test");
std::shared_ptr<B> spB = creator.create<B>(std::vector<float>({0.1f,0.2f,0.3f}));
std::shared_ptr<C> spC = creator.create<C>(67);
触发虚拟成员函数而不是模板成员函数:
现在假设我们需要工厂允许以不同的方式创建对象 A 和 C。
为此,我们为工厂添加了两个虚函数,当处理的对象是 A 或 C 时,这两个虚函数将被触发,而不是模板创建函数。然后我们可以创建派生工厂 classes,它可以处理这些对象以我们希望的不同方式。
为简单起见,让我们在 - 替换函数 中调用这些虚函数,因为它们打算被触发而不是特定类型的模板。
!! 注意替换函数与模板函数的形式相同。
!! 注意替换 const/non const 类型与模板相同。 在我们的示例中模板创建函数是一个 const 函数,因此我们也必须将替换函数设为 const。
// 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>;
让我们创建一个在创建 A 和 C 时进行不同处理的派生工厂
// 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;
}
};
但这行不通!
让我们检查一下。
下面运行我们构造一个FactoryEve类型的creator,以便在创建A和C时得到不同的待遇
跟踪调用显示所有创建都是使用模板 Factory::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
这是为什么?
因为我们实际上只调用模板表单 - 请参阅包含调用行的函数 Creator::create:
T* p = m_spFactory->create<T>(std::forward<Args>(parametes)...);
我们使用模板参数调用创建,这意味着 - 仅调用模板函数,编译器完全按照我们的要求执行。
因此,为了让编译器找到匹配的非模板函数,我们必须将行更改为。
T* p = m_spFactory->create(std::forward<Args>(parametes)...);
这样一来,编译器会选择类型 T 的最佳匹配项。如果该类型有显式函数,它会优先选择它,否则,它会使用模板一。
!! 当调用可能具有非模板替换函数或不同模板参数函数的模板函数时,调用时不要使用模板参数。
但是现在,如果你去掉模板参数,你会得到一个编译错误:(
这是为什么?
因为编译器无法根据return类型找到正确的函数,这是我们函数的形式。
!! 无法根据 return 类型进行替换。
当我们使用模板参数时,编译器确切地知道要采用什么函数,但我们需要在没有模板参数的情况下调用 create 以允许由非模板函数替换。
因此,我们必须更改函数形式,使函数参数中包含对象类型。
这里是 Factory 对象的固定代码,派生的 class FactoryEve 应该相应固定。
// 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;
};
对象 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;
};
好的,如果我们现在 运行 它,我们会得到改进,但是,它不会按需要做所有事情。
跟踪调用显示,对于对象 C,它按预期使用 C 的 FactoryEve::create,但对于对象 A,它仍然使用 Factory 基类的模板函数 class .
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)
这是为什么?
因为我们为创建 A 给出的输入参数 (4,”test”) 的参数包类型被视为:
int, const char[5]
因此,对于对象 A,对于行 m_spFactory->create(p, std::forward(parametes)...);编译器搜索具有
形式的函数
void Factory::create(A*&, int&&, const char[5]&) const
但是我们为 A 声明的虚函数具有不同的形式并且具有 std::string 而不是 char[5]
void create(A*& o_p, int i_i, const std::string& i_s) const
这就是为什么它不适用于 A,而仅适用于 C。
问题是当编译器选择匹配函数时,它没有考虑转换。
那我们能做什么呢?我们不想强制应用程序使用 std::string 但保持友好,我们不想为每个可能的转换类型编写虚函数,因为它使我们的代码与许多函数一起沸腾,并且我们肯定会忘记某种……好像真的很可怕!
幸运的是,我们有解决方案。让我们使用参数包本身作为我们替换函数的输入参数。这样,它确保了编译器从应用程序调用中获得的任何类型,我们的函数将具有相同的形式!
!! 替换带参数包的函数时,也更喜欢使用带参数包的函数。
原则上,我们想做这样的事情
// function replacement for A
template<typename... Args>
virtual void create(A*& o_p, Args&&...parametes) const
{
o_p = new A(i_i, i_s);
}
但是我们不能,因为虚函数不能是模板!
哈!看来我们只是从一个问题到另一个问题。
好吧,幸运的是,我们可以使用调用虚函数的模板替换函数轻松解决它,如下所示:
(请注意,虚函数现在每个都有一个唯一的名称 createA 和 create C)
// 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;
};
通过这种方式,我们在使用相同参数包的同时替换了通用的创建模板函数,这确保我们获得相同的表单,而且我们仍然拥有虚拟机制,允许不同的工厂类型用于不同的创建方法.
现在可以使用了!
不要忘记将 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
最后的话:
对于使用虚函数替换带参数包的模板成员函数,我们实际上不需要将它们用作替换,而是从不同的模板替换函数中调用它们。
- 注意替换函数会有相同的
表单作为模板之一 - 还要注意 const/non const
函数类型。
- 调用可能有非模板的模板函数时
替换函数,或不同的模板参数函数,调用时不带模板参数。
- 无法根据 return 类型进行替换。因此,如果你的类型
是唯一一个标识函数,把它作为参数。
- 替换带参数包的函数时,优先使用具有相同参数包的替换函数。
我有一个模板成员函数,我想为大多数类型调用它,但对于某些特定类型,我需要调用虚拟成员函数。
类似这样的东西(请不要关注“工厂设计”,它只是为了提出 c++ 问题,而不是因为这是工厂必然需要的设计):
// factory
class Factory
{
// default create function
template<typename T, typename... Args>
T* create(Args&&...parametes) const
{
return new T(std::forward<Args>(parametes)...);
}
// Handling creation for type A
virtual A* create(int i_i, const std::string& i_s) const =0;
// Handling creation for type C
virtual C* create(int i_i) const = 0;
};
使用例如:
Factory* pFactory = new DerivedFactoryObject;
A* pA = pFactory->creat<A>(4,"Test");
但它总是调用模板函数而不是 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;
但是实际上不可能对函数进行偏特化,确实编译失败了。
那我该怎么做呢?
我花了好几天的时间才弄清楚如何去做,所以我很乐意在这里给出我的结论作为帮助其他人理解我们可能遇到的细节的教程。它对更正和改进开放,这就是为什么我把它写在这里作为一个问题。
为了说明所涉及的问题,我用一个小例子逐步解释了这个主题。在这个例子中,我们希望使用工厂构建一个对象创建器,在这里我们可以使用不同类型的工厂来获得不同的对象创建方式。
基本版:
首先,让我们从工厂的基本版本开始。
// 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>;
这个工厂可以使用它的模板函数 create 创建不同类型的对象,它是私有的,只有 Creator 对象可以使用它 - 这就是我们声明 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<T>(std::forward<Args>(parametes)...);
return std::shared_ptr<T>(p);
}
private:
FactorySPtr m_spFactory;
};
构造时,它存储将用于创建对象的工厂。
为了展示它是如何使用的,假设我们有以下对象 A、B 和 C:
struct A
{
A(int i_i, const std::string& i_s) : i(i_i), s(i_s) {}
int i = 0;
std::string s;
};
struct B
{
B(const std::vector<float>& i_v) : v(i_v) {}
std::vector<float> v;
};
struct C
{
C(int i_i) : i(i_i) {}
int i = 0;
};
那么我们就可以使用creator如下:
Creator creator(std::make_shared<Factory>());
std::shared_ptr<A> spA = creator.create<A>(4, "test");
std::shared_ptr<B> spB = creator.create<B>(std::vector<float>({0.1f,0.2f,0.3f}));
std::shared_ptr<C> spC = creator.create<C>(67);
触发虚拟成员函数而不是模板成员函数:
现在假设我们需要工厂允许以不同的方式创建对象 A 和 C。
为此,我们为工厂添加了两个虚函数,当处理的对象是 A 或 C 时,这两个虚函数将被触发,而不是模板创建函数。然后我们可以创建派生工厂 classes,它可以处理这些对象以我们希望的不同方式。
为简单起见,让我们在 - 替换函数 中调用这些虚函数,因为它们打算被触发而不是特定类型的模板。
!! 注意替换函数与模板函数的形式相同。
!! 注意替换 const/non const 类型与模板相同。 在我们的示例中模板创建函数是一个 const 函数,因此我们也必须将替换函数设为 const。
// 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>;
让我们创建一个在创建 A 和 C 时进行不同处理的派生工厂
// 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;
}
};
但这行不通!
让我们检查一下。
下面运行我们构造一个FactoryEve类型的creator,以便在创建A和C时得到不同的待遇
跟踪调用显示所有创建都是使用模板 Factory::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
这是为什么?
因为我们实际上只调用模板表单 - 请参阅包含调用行的函数 Creator::create:
T* p = m_spFactory->create<T>(std::forward<Args>(parametes)...);
我们使用模板参数调用创建,这意味着 - 仅调用模板函数,编译器完全按照我们的要求执行。
因此,为了让编译器找到匹配的非模板函数,我们必须将行更改为。
T* p = m_spFactory->create(std::forward<Args>(parametes)...);
这样一来,编译器会选择类型 T 的最佳匹配项。如果该类型有显式函数,它会优先选择它,否则,它会使用模板一。
!! 当调用可能具有非模板替换函数或不同模板参数函数的模板函数时,调用时不要使用模板参数。
但是现在,如果你去掉模板参数,你会得到一个编译错误:(
这是为什么?
因为编译器无法根据return类型找到正确的函数,这是我们函数的形式。
!! 无法根据 return 类型进行替换。
当我们使用模板参数时,编译器确切地知道要采用什么函数,但我们需要在没有模板参数的情况下调用 create 以允许由非模板函数替换。
因此,我们必须更改函数形式,使函数参数中包含对象类型。
这里是 Factory 对象的固定代码,派生的 class FactoryEve 应该相应固定。
// 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;
};
对象 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;
};
好的,如果我们现在 运行 它,我们会得到改进,但是,它不会按需要做所有事情。
跟踪调用显示,对于对象 C,它按预期使用 C 的 FactoryEve::create,但对于对象 A,它仍然使用 Factory 基类的模板函数 class .
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)
这是为什么?
因为我们为创建 A 给出的输入参数 (4,”test”) 的参数包类型被视为:
int, const char[5]
因此,对于对象 A,对于行 m_spFactory->create(p, std::forward(parametes)...);编译器搜索具有
形式的函数void Factory::create(A*&, int&&, const char[5]&) const
但是我们为 A 声明的虚函数具有不同的形式并且具有 std::string 而不是 char[5]
void create(A*& o_p, int i_i, const std::string& i_s) const
这就是为什么它不适用于 A,而仅适用于 C。
问题是当编译器选择匹配函数时,它没有考虑转换。
那我们能做什么呢?我们不想强制应用程序使用 std::string 但保持友好,我们不想为每个可能的转换类型编写虚函数,因为它使我们的代码与许多函数一起沸腾,并且我们肯定会忘记某种……好像真的很可怕!
幸运的是,我们有解决方案。让我们使用参数包本身作为我们替换函数的输入参数。这样,它确保了编译器从应用程序调用中获得的任何类型,我们的函数将具有相同的形式!
!! 替换带参数包的函数时,也更喜欢使用带参数包的函数。
原则上,我们想做这样的事情
// function replacement for A
template<typename... Args>
virtual void create(A*& o_p, Args&&...parametes) const
{
o_p = new A(i_i, i_s);
}
但是我们不能,因为虚函数不能是模板!
哈!看来我们只是从一个问题到另一个问题。
好吧,幸运的是,我们可以使用调用虚函数的模板替换函数轻松解决它,如下所示:
(请注意,虚函数现在每个都有一个唯一的名称 createA 和 create C)
// 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;
};
通过这种方式,我们在使用相同参数包的同时替换了通用的创建模板函数,这确保我们获得相同的表单,而且我们仍然拥有虚拟机制,允许不同的工厂类型用于不同的创建方法.
现在可以使用了!
不要忘记将 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
最后的话:
对于使用虚函数替换带参数包的模板成员函数,我们实际上不需要将它们用作替换,而是从不同的模板替换函数中调用它们。
- 注意替换函数会有相同的 表单作为模板之一 - 还要注意 const/non const 函数类型。
- 调用可能有非模板的模板函数时 替换函数,或不同的模板参数函数,调用时不带模板参数。
- 无法根据 return 类型进行替换。因此,如果你的类型 是唯一一个标识函数,把它作为参数。
- 替换带参数包的函数时,优先使用具有相同参数包的替换函数。