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

#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;
}