gpt4 book ai didi

c++ - C++模板和运行时

转载 作者:行者123 更新时间:2023-12-02 10:33:15 25 4
gpt4 key购买 nike

我想创建一个模板工厂类,使得给定一个int i,它将在其参数列表中创建第i个类的实例;我必须是一个运行时变量。这个想法开始如下:假设我们有类型A,B。我们可以轻松地在下面创建类:

class factory{
void* create(size_t i) {
return (i==0) new A() : (i==1 ? new B() :nullptr);
}
};

我们必须使用 void*作为返回类型,但这是可行的。现在我们如何使用模板扩展它,以便我们可以做到:

auto f = factory<A,B,C,D,E,F>();
A* a = f.create(0);
E* e = f.create(4);

我已经花了整整10个小时的时间,并提出了一个解决方案,如果在编译时知道我的话,该解决方案将起作用。这里是:

template <size_t i, class first, class... rest>
struct choose: public choose<i - 1, rest...> {};

template <class first, class... rest>
struct choose<0, first, rest...> {
using type = first;
};

template<class... cls>
class factory {
public:
template <size_t j, typename... ArgTypes>
inline typename choose<j, cls...>::type* create(ArgTypes... args) {
using f = typename choose<j, cls...>::type;
return new f(args...);
}
};

问题在于变量j需要在编译时知道,这不是我想要的。
我也不想创建对象,将它们放入数组中,然后从数组中获取它。我知道这会使我的痛苦消失,但是本练习的目的是学习模板。

此代码的上下文适用于我正在使用c++制作的简单Web框架。我想要 Controller 类和应用程序类:

class Controller {
virtual get(params) =0;
virtual post(params) =0;
};
class ControllerA: Controller {
public:
constexpr static char route[] = "/home"; //this controller handles this route
// virtual implementation
};
class ControllerB: Controller {
public:
constexpr static char route[] = "/user";
// virtual implementation
};

template<class... controllers>
class Application {
factory<controllers...> f;
public:
Application() {
//create router and give it all of the routes from the controllers in the template.
}
dispatchPostRequest(request) {
int i = doRounting(request.route); //router returns a number that specifies the
//index of controller in the template parameter pack.
f.create(i) -> post()
}
};


对我来说,这似乎是一个简单的概念。 Java / JS / Python的实现每个要花20分钟。我不明白为什么我在C++中如此艰难。

最佳答案

I also don't want to create the objects, put them into an array [...]



这可以作为可能解决方案的基础;尽管您不会将对象添加到该数组中,但会创建函数。

但是,您非常简单的代码已经出现了内存泄漏:
f.create(i) -> post();

什么时候再次删除对象???因此,通过返回智能指针,使创建者函数安全!

同样,通过 void*进行操作也不是安全的(除了防止使用智能指针-您不能 delete无效指针!),您也可以很容易地应用错误的类型转换,然后:
std::string* s = static_cast<std::string*>(create<std::string, std::complex<double>, std::vector<int>>(1));

看到问题了吗?但是,有了 Controller基类,您已经具有保持工厂函数(或类)安全所需的所有必要基础结构!因此,可能的解决方案如下所示:
template <typename T>
std::unique_ptr<Controller> makeT()
{
return std::make_unique<T>();
}

template <typename ... Types>
std::unique_ptr<Controller> create(size_t index)
{
static std::unique_ptr<Controller>(*creators[])() =
#if 0
{ &std::make_unique<Types> ... };
#else
{ &makeT<Types>... };
#endif
return creators[index]();
}

不幸的是,我们不能直接使用 std::make_unique,因为每个实例化都有不同的返回类型(特定类的unique_ptr!),因此我们得到了不兼容的指针。所以我们需要那个中间函数...

由于智能指针(避免显式删除的必要性)和多态性(避免需要正确的强制转换),上述调用现在是安全的。

关于c++ - C++模板和运行时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61451788/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com