如何使用可变参数模板在 C++ 中概括对象创建?
How to generalize object creation in C++ using variadic templates?
我正在尝试用 C++ 创建一个通用工厂方法,它可以创建许多(但数量有限)对象之一的实例。每个对象都需要不同类型的参数来构造,所以我希望该方法以某种方式推断出所需的类型,而不想让用户明确指定它。
这里有一些代码来说明我正在尝试做的事情:
#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... };
}
现在,main
函数中的代码可以通过调用 Make
来创建 A *
和 B *
类型的对象,如下所示:
A *a = Make<A>(3, 4);
B *b = Make<B>(3.14f, 6.28f);
有没有一种方法可以扩展此代码以使其他函数能够调用 Make
而无需明确指定它们是想要 A *
还是 B *
的实例?例如,
A * a = Make(3, 4); // (int, int)
B * b = Make(3.14f, 6.28f); // (float, float)
我知道函数模板是使用参数类型推导来实例化的,return 类型不参与其中。但是,编译器不会进行任何类型转换。所以 Make(int, int)
绝对是与 Make(float, float)
不同的实例,我希望能够利用它来将函数定义映射到正确的 return 类型。
这是我的尝试:
定义显式实例化
template A * Make(int x, int y);
定义专业
template<>
A * Make<A, int, int>(int x, int y);
两者都没有按预期工作。关于如何实现这一点有什么想法吗?
我写了一个 Maker
帮助程序模板来注册哪些 类 是允许的,虽然我不知道如何禁用基本模板:
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)
}
您可能会向工厂提供所需的信息,class 组构造,以及所需的参数 (*)。
(*): (注意:如果您的 classes 具有正确的属性,您甚至可以使用 magic_get.
自动检测构造函数的参数
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)
我正在尝试用 C++ 创建一个通用工厂方法,它可以创建许多(但数量有限)对象之一的实例。每个对象都需要不同类型的参数来构造,所以我希望该方法以某种方式推断出所需的类型,而不想让用户明确指定它。
这里有一些代码来说明我正在尝试做的事情:
#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... };
}
现在,main
函数中的代码可以通过调用 Make
来创建 A *
和 B *
类型的对象,如下所示:
A *a = Make<A>(3, 4);
B *b = Make<B>(3.14f, 6.28f);
有没有一种方法可以扩展此代码以使其他函数能够调用 Make
而无需明确指定它们是想要 A *
还是 B *
的实例?例如,
A * a = Make(3, 4); // (int, int)
B * b = Make(3.14f, 6.28f); // (float, float)
我知道函数模板是使用参数类型推导来实例化的,return 类型不参与其中。但是,编译器不会进行任何类型转换。所以 Make(int, int)
绝对是与 Make(float, float)
不同的实例,我希望能够利用它来将函数定义映射到正确的 return 类型。
这是我的尝试:
定义显式实例化
template A * Make(int x, int y);
定义专业
template<> A * Make<A, int, int>(int x, int y);
两者都没有按预期工作。关于如何实现这一点有什么想法吗?
我写了一个 Maker
帮助程序模板来注册哪些 类 是允许的,虽然我不知道如何禁用基本模板:
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)
}
您可能会向工厂提供所需的信息,class 组构造,以及所需的参数 (*)。
(*): (注意:如果您的 classes 具有正确的属性,您甚至可以使用 magic_get.
自动检测构造函数的参数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)