You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
2.9 KiB
151 lines
2.9 KiB
2 years ago
|
#include <iostream>
|
||
|
#include <string>
|
||
|
#include <functional>
|
||
|
#include <unordered_map>
|
||
|
#include <string_view>
|
||
|
// 自动注册实现
|
||
|
|
||
|
template<typename T>
|
||
|
constexpr auto type_name() noexcept {
|
||
|
std::string_view name, prefix, suffix;
|
||
|
#ifdef __clang__
|
||
|
name = __PRETTY_FUNCTION__;
|
||
|
prefix = "auto type_name() [T = ";
|
||
|
suffix = "]";
|
||
|
#elif defined(__GNUC__)
|
||
|
name = __PRETTY_FUNCTION__;
|
||
|
prefix = "constexpr auto type_name() [with T = ";
|
||
|
suffix = "]";
|
||
|
#elif defined(_MSC_VER)
|
||
|
name = __FUNCSIG__;
|
||
|
prefix = "auto __cdecl type_name<";
|
||
|
suffix = ">(void) noexcept";
|
||
|
#endif
|
||
|
name.remove_prefix(prefix.size());
|
||
|
name.remove_suffix(suffix.size());
|
||
|
return name;
|
||
|
}
|
||
|
|
||
|
// 基类
|
||
|
class Base {
|
||
|
public:
|
||
|
virtual const std::string_view className() const {
|
||
|
return "base";
|
||
|
};
|
||
|
|
||
|
virtual ~Base() {
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
using BFun = std::function<Base *()>;
|
||
|
using BMap = std::unordered_map<std::string_view, BFun>;
|
||
|
|
||
|
class Dic {
|
||
|
public:
|
||
|
|
||
|
static void reg(std::string_view className, const BFun &fun) {
|
||
|
getMap().insert(std::make_pair(className, fun));
|
||
|
}
|
||
|
|
||
|
static BMap &getMap() {
|
||
|
static BMap bMap;
|
||
|
return bMap;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename T>
|
||
|
class BaseObj : public virtual Base {
|
||
|
|
||
|
public:
|
||
|
|
||
|
const std::string_view className() const override {
|
||
|
return allocator.className();
|
||
|
}
|
||
|
|
||
|
static const std::string_view getClassName() {
|
||
|
return allocator.className();
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
BaseObj() {};
|
||
|
|
||
|
~BaseObj() override = default;
|
||
|
|
||
|
private:
|
||
|
class Allocator {
|
||
|
public:
|
||
|
Allocator() {
|
||
|
registerClass<T>();
|
||
|
}
|
||
|
|
||
|
const std::string_view &className() const {
|
||
|
static std::string_view class_name = type_name<T>();
|
||
|
return class_name;
|
||
|
}
|
||
|
|
||
|
template<typename D>
|
||
|
typename std::enable_if<std::is_default_constructible<D>::value,
|
||
|
void>::type
|
||
|
registerClass() {
|
||
|
Dic::reg(className(), []() -> Base * { return new T(); });
|
||
|
}
|
||
|
|
||
|
template<typename D>
|
||
|
typename std::enable_if<!std::is_default_constructible<D>::value,
|
||
|
void>::type
|
||
|
registerClass() {
|
||
|
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static Allocator allocator;
|
||
|
};
|
||
|
|
||
|
template<typename T>
|
||
|
typename BaseObj<T>::Allocator BaseObj<T>::allocator;
|
||
|
|
||
|
|
||
|
//
|
||
|
class A : public BaseObj<A> {
|
||
|
public:
|
||
|
};
|
||
|
|
||
|
|
||
|
class B : public BaseObj<B> {
|
||
|
public:
|
||
|
};
|
||
|
|
||
|
|
||
|
// 工厂类
|
||
|
class Factory {
|
||
|
|
||
|
public:
|
||
|
static Base *create(const std::string & className) {
|
||
|
BMap map = Dic::getMap();
|
||
|
auto iter = map.find(className);
|
||
|
if (iter != map.end()) {
|
||
|
return iter->second();
|
||
|
}
|
||
|
return nullptr;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
int main() {
|
||
|
|
||
|
auto aa = Factory::create("A");
|
||
|
auto bb = Factory::create("B");
|
||
|
|
||
|
if (aa != nullptr) {
|
||
|
std::cout << aa->className() << std::endl;
|
||
|
}
|
||
|
|
||
|
if (bb != nullptr) {
|
||
|
std::cout << bb->className() << std::endl;
|
||
|
}
|
||
|
|
||
|
std::cout << "hello world!" << std::endl;
|
||
|
|
||
|
return 0;
|
||
|
}
|