如何在C++;使用可变模板? 我试图在C++中创建一个通用的工厂方法,它可以创建许多(但有限数量)对象之一的实例。每个对象都需要不同类型的参数来构造,因此我希望该方法能够以某种方式推断出所需的类型,而不希望用户显式地指定它
下面是一些代码来说明我要做的事情:如何在C++;使用可变模板? 我试图在C++中创建一个通用的工厂方法,它可以创建许多(但有限数量)对象之一的实例。每个对象都需要不同类型的参数来构造,因此我希望该方法能够以某种方式推断出所需的类型,而不希望用户显式地指定它,c++,templates,variadic-templates,generic-programming,C++,Templates,Variadic Templates,Generic Programming,下面是一些代码来说明我要做的事情: #include <iostream> using namespace std; class A { public: A(int x, int y) { cout << "A(" << x << ", " << y << ")\n"; } }; class B { public: B(float a, float b) { cou
#include <iostream>
using namespace std;
class A {
public:
A(int x, int y) {
cout << "A(" << x << ", " << y << ")\n";
}
};
class B {
public:
B(float a, float b) {
cout << "B(" << a << ", " << b << ")\n";
}
};
template<typename T, typename... Ts>
T * Make(Ts... vs) {
puts(__PRETTY_FUNCTION__); // __FUNCSIG__ or __PRETTY_FUNCTION__
return new T{ vs... };
}
是否有一种方法可以扩展此代码,使其他函数能够调用Make
,而无需明确指定它们是否需要a*
或B*
的实例?比如说,
A * a = Make(3, 4); // (int, int)
B * b = Make(3.14f, 6.28f); // (float, float)
我知道函数模板是使用参数类型推断进行实例化的,返回类型不在其中。但是,编译器不会进行任何类型转换。因此Make(int,int)
与Make(float,float)
绝对是不同的实例,我希望能够利用它将函数定义映射到正确的返回类型
以下是我尝试过的:
- 定义显式实例化
template A * Make(int x, int y);
- 定义专门化
template<> A * Make<A, int, int>(int x, int y);
模板 A*Make(整数x,整数y);
这两种方法都没有达到预期效果。关于如何实现这一点有什么想法吗?我编写了一个
Maker
helper模板,用于注册允许的类,尽管我不知道如何禁用基本模板:
template <typename... Ts>
struct Maker {
using type = void;
};
template <>
struct Maker<int, int> {
using type = A;
};
template <>
struct Maker<float, float> {
using type = B;
};
template<typename... Ts, typename T=typename Maker<Ts...>::type>
T * Make(Ts... vs) {
puts(__PRETTY_FUNCTION__); // __FUNCSIG__ or __PRETTY_FUNCTION__
return new T{ vs... };
}
int main() {
A * a = Make(3, 4); // (int, int)
B * b = Make(3.14f, 6.28f); // (float, float)
}
模板
结构生成器{
使用类型=无效;
};
样板
结构生成器{
使用类型=A;
};
样板
结构生成器{
使用类型=B;
};
样板
T*Make(Ts…vs){
puts(uuu PRETTY_函数);/uu FUNCSIG_uuu或uu PRETTY_函数__
返回新的T{vs..};
}
int main(){
A*A=Make(3,4);/(int,int)
B*B=Make(3.14f,6.28f);/(浮动,浮动)
}
我编写了一个Maker
helper模板,用于注册允许的类,尽管我不知道如何禁用基本模板:
template <typename... Ts>
struct Maker {
using type = void;
};
template <>
struct Maker<int, int> {
using type = A;
};
template <>
struct Maker<float, float> {
using type = B;
};
template<typename... Ts, typename T=typename Maker<Ts...>::type>
T * Make(Ts... vs) {
puts(__PRETTY_FUNCTION__); // __FUNCSIG__ or __PRETTY_FUNCTION__
return new T{ vs... };
}
int main() {
A * a = Make(3, 4); // (int, int)
B * b = Make(3.14f, 6.28f); // (float, float)
}
模板
结构生成器{
使用类型=无效;
};
样板
结构生成器{
使用类型=A;
};
样板
结构生成器{
使用类型=B;
};
样板
T*Make(Ts…vs){
puts(uuu PRETTY_函数);/uu FUNCSIG_uuu或uu PRETTY_函数__
返回新的T{vs..};
}
int main(){
A*A=Make(3,4);/(int,int)
B*B=Make(3.14f,6.28f);/(浮动,浮动)
}
您可以向工厂提供所需的信息、要构造的类集以及所需的参数(*)
(*):(注意:如果您的类具有正确的属性,您甚至可以使用自动检测构造函数的参数
您可以向工厂提供所需的信息、要构造的类集以及所需的参数(*) (*):(注意:如果您的类具有正确的属性,您甚至可以使用自动检测构造函数的参数
OT:最好在make函数中使用完美转发:
T*make(Ts&&…vs)
和返回新的T{std::forward(vs)};
.OT:最好在make函数中使用完美转发:T*make(Ts&…vs)
和返回新的T{std::forward(vs)}
。这太好了!我想基本模板可以写为有一个空的结构生成器{}
,没有任何类型字段,然后可以与enable\u if(从type\u traits)一起使用因此Make的定义仅适用于已知类型。哦,如果您在C++14模式下编译,您可以停止使用type=void(针对给定示例进行编译,并为egMake()
)抛出一个错误@Botje:即使在C++11中也是如此。(但之前不会,因为变量模板和函数的默认模板参数)太棒了!我想基本模板可以编写成一个空的structmaker{}
,没有任何类型字段,然后可以与enable_if(来自type_traits)一起使用,这样Make的定义就只能用于已知的类型。哦,如果你在C++14模式下编译,你可以不用使用type=void
。(针对给定的示例进行编译,并为egMake()
)抛出一个错误@Botje:即使在C++11中也是如此。(但之前不是这样,因为变量模板和函数的默认模板参数)。在constepr Maker Make{};
行中是模板参数(例如,A(int,int)
)函数类型?对于std::function
,函数的签名很吸引人。constepr Maker{};
行中是模板参数(例如,A(int,int)
)函数类型?对于std::function
,函数的签名
template <typename ... Sigs> struct Maker : Maker<Sigs>...
{
using Maker<Sigs>::operator ()...;
// Do we want to accept conversions or not in non ambiguous cases ?
//template <typename ... Ts> operator()(Ts/*&&*/...) const = delete;
};
template <class C, typename ... Args> struct Maker<C(Args...)>
{
C operator()(Args... args) const {
puts(__PRETTY_FUNCTION__); // __FUNCSIG__ or __PRETTY_FUNCTION__
return C(std::forward<Args>(args)...); // not {} to avoid initializer_list constructor
}
};
constexpr Maker<A(int, int), B(float, float)> Make{};
A a = Make(3, 4); // (int, int)
B b = Make(3.14f, 6.28f); // (float, float)