如何在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(针对给定示例进行编译,并为eg
Make()
)抛出一个错误@Botje:即使在C++11中也是如此。(但之前不会,因为变量模板和函数的默认模板参数)太棒了!我想基本模板可以编写成一个空的
structmaker{}
,没有任何类型字段,然后可以与enable_if(来自type_traits)一起使用,这样Make的定义就只能用于已知的类型。哦,如果你在C++14模式下编译,你可以不用
使用type=void
。(针对给定的示例进行编译,并为eg
Make()
)抛出一个错误@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)