gpt4 book ai didi

c++ - 模板化自动工厂注册

转载 作者:行者123 更新时间:2023-12-01 14:53:20 25 4
gpt4 key购买 nike

想象一下,我有一些对象都与某个接口(interface)类库相关。但是,所有这些对象都由某个整数 DIM 模板化。 (方面)。我假设 base 的所有衍生物都有一个静态成员 int number()和一个静态字符串 InputName .想法是注册这个静态方法 number()。 (真的每个类都有完整的静态接口(interface)。)

注册.hpp

template <int DIM>
class objectRegistry
{
public:
template<typename T>
Register()
{
//something like interface_map[T::InputName] = T::number;
}
private:
static inline std::map<std::string, std::function<int ()>> interface_map;
}


Header1.hpp

template <int DIM>
class base
{
public:
static inline const std::string InputName = "base";
static int number() { return 1; };
base(){};
};
//todo: Some Registration Here

Header2.hpp

template <int DIM>
class derived : public base<DIM>, public AutomaticRegister<DIM, derived<DIM>>
{
public:
static inline std::string InputName = "derived";
static int number() { return 4; };
derived(){};
};

//todo: Some Registration Here

听者3.hpp

template <int DIM, typename extra_type>
class derived2 : public base<DIM>, public AutomaticRegister<DIM, derived2<DIM,extra_type>>
{
public:
static inline std::string InputName = "derived2 " + std::string(typeid(extra_type).name());
static int number() { return 5; };

extra_type member;
};

//todo: Some Registration Here


我可以为派生对象创建一个自动注册系统(所有从基础派生);理想情况下,它与对象定义存在于同一头文件中。例如,我希望 objectRegistry<3> 知道 derived<3>、derived2<3,int> 和 derived<3,double> 存在。我试过这些方法:

Best way to for C++ types to self register in a list?
https://www.bfilipek.com/2018/02/factory-selfregister.html

然而,因为一切都埋在 template< int DIM> ,它永远不会被实例化。

有什么办法可以强制 derivedobjectRegistry 时实例化用特定的模板值实例化?

最佳答案

您链接到的两种方法中的任何一种都可以使用。

您的问题是您使用的是类模板,而不是类。

如果你这样做了

class Something : public AutomaticRegister<Something>
{
// ...
};

那么你会得到自动注册,因为 Something是一类。

您有类模板,它们根本不像类型。
注册是通过实例化注册类来进行的,注册类是类模板的基类。

因此,为了实例化注册类,您需要将要注册的内容视为一种类型。因此,您需要通过创建模板之一的实例来实例化类的某些部分......

derived2<1, double> d2_1_double;

或通过显式实例化整个类模板...

template class derived2<1, double>;

或通过显式实例化类模板的某些成员,例如 number 函数...

template int derived2<1, double>::number();

或者通过创建一个实际的派生类...

struct d2_1_double : derived2<1, double> { };

或其他方式从类模板中删除类。

但是,注册类模板的一个非常小的更改(添加类型成员别名)为我们提供了一种显式批量注册它们的机制,并且不需要从注册机制继承。

为了演示,我添加了一些非常简单的非生产质量代码。为此,我添加了一个非标准函数来获取适用于 gcc 和 clang 的类型的唯一名称,但不了解其他编译器。这不是必需的,只是让我更容易。

#include <functional>
#include <iostream>
#include <string_view>
#include <unordered_map>

template <typename ... Ts> struct TypeList { };

template <typename T>
constexpr auto
fname()
{
return __PRETTY_FUNCTION__;
}

class Registry
{
std::unordered_map<std::string_view, std::function<int()>> map;

public:
void insert(std::string_view key, std::function<int()> value) {
assert(map.find(key) == map.end());
std::cout << "Register \"" << key << "\", " << value() << '\n';
map[key] = std::move(value);
}
int operator()(std::string_view key) const {
return map.at(key)();
}
};

template <int DIM>
Registry & registry()
{
static Registry result;
return result;
}

这是自动注册的东西, the answer 的修改版本从您的链接之一。

template <typename T>
class AutoRegister
{
struct helper {
helper() { registry<T::dim>().insert(fname<T>(), T::number); }
};
/* inline */ static helper h;
template<helper&> struct ref { using type = AutoRegister; };
public:
using type = typename ref<h>::type;
};
// NOTE: A bug in gcc forces this usage rather than just using inline.
template <typename T>
typename AutoRegister<T>::helper AutoRegister<T>::h;

然后,使用一些类似于您的类模板...

template <int DIM>
struct Bar
{
static constexpr int dim = DIM;
static int number() { return dim*100 + 99; }
};
template <int DIM, typename T>
struct Baz
{
static constexpr int dim = DIM;
static int number() { return dim*100 + 86; }
};
template <int DIM, typename ... Ts>
struct Foo
{
static constexpr int dim = DIM;
static int number() { return dim*100 + 42; }
};

和一个助手别名模板...

template <typename ... Ts>
using RegisterTypes = TypeList<typename AutoRegister<Ts>::type...>;

我们可以注册我们想要的东西。第二个有一些重复,只是为了表明东西被注册了一次。

using Registered = RegisterTypes<Bar<0>, Bar<1>, Baz<1>, Foo<1>>;
using Registered2 = RegisterTypes<Bar<2>, Bar<1>, Baz<1>, Foo<1>>;

int main()
{
}

运行程序会产生以下输出...
Register "auto fname() [T = Bar<0>]", 99
Register "auto fname() [T = Bar<1>]", 199
Register "auto fname() [T = Baz<1, int>]", 186
Register "auto fname() [T = Foo<1, int>]", 142
Register "auto fname() [T = Bar<2>]", 299
Register "auto fname() [T = Foo<1, int, double>]", 142```

关于c++ - 模板化自动工厂注册,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60728688/

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