高级农民
- 积分
- 3340
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2017-6-18
- 最后登录
- 1970-1-1
|
第一个问题要带类型检查的话其实非常麻烦,因为需要在编译期做很多事情,我写了一份参考代码,测试环境用的Clang编译器和C++14,楼主有兴趣的话可以研究一下..
- #include <iostream>
- #include <memory>
- #include <string>
- #include <type_traits>
- #include <utility>
- ////////////////////////////////////////////////////////////////////////////////
- /////////////////////////// 作为例子的简易Base类和两个子类 //////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- class Base {
- public:
- virtual ~Base() {}
- virtual void Run() = 0;
- template <typename... Ts>
- static Base* Instantiate(const std::string& name, Ts&&... args);
- };
- class DerivedExample : public Base {
- public:
- void Run() override { std::cout << "DerivedExample\n"; }
- static std::string GetName() { return "DerivedExample"; }
- };
- class AnotherExample : public Base {
- public:
- AnotherExample(int value, const std::string& name)
- : value_(value), name_(name) {}
- void Run() override {
- std::cout << "AnotherExample " << value_ << " " << name_ << "\n";
- }
- static std::string GetName() { return "AnotherExample"; }
- private:
- int value_;
- std::string name_;
- };
- ////////////////////////////////////////////////////////////////////////////////
- ////////// 用于compile-time类型计算的TypeList, 这里只实现了一小部分相关功能 ////////////
- ////////////////////////////////////////////////////////////////////////////////
- // 这部分代码虽然写了一大堆,但主要只是为了搭建出 MetaFilter 和 MetaCartesianProduct
- // 这两个meta method 以及 ForEach 这一个static method,可以先跳过..
- template <typename ...Ts> class TypeList;
- namespace meta_internal {
- using EmptyList = TypeList<>;
- template <typename TL, typename Out, std::size_t rest, typename Enable = void>
- struct MetaTake;
- template <typename TL, typename Out, std::size_t rest>
- struct MetaTake<TL, Out, rest, std::enable_if_t<rest == 0>> {
- using type = Out;
- };
- template <typename TL, typename Out, std::size_t rest>
- struct MetaTake<TL, Out, rest, std::enable_if_t<rest != 0>>
- : MetaTake<typename TL::tail,
- typename Out::template MetaPushBack<typename TL::head>,
- rest - 1> {};
- template <typename TL, std::size_t rest, typename Enable = void>
- struct MetaSkip;
- template <typename TL, std::size_t rest>
- struct MetaSkip<TL, rest, std::enable_if_t<rest == 0>> {
- using type = TL;
- };
- template <typename TL, std::size_t rest>
- struct MetaSkip<TL, rest, std::enable_if_t<rest != 0>>
- : MetaSkip<typename TL::tail, rest - 1> {};
- template <typename TL, typename TailTL>
- struct MetaAppend;
- template <typename ...Ts, typename ...Tails>
- struct MetaAppend<TypeList<Ts...>, TypeList<Tails...>> {
- using type = TypeList<Ts..., Tails...>;
- };
- template <typename Out, typename Rest, template <typename ...> class Op,
- typename Enable = void>
- struct MetaFilter;
- template <typename Out, typename Rest, template <typename ...> class Op>
- struct MetaFilter<Out, Rest, Op, std::enable_if_t<Rest::length == 0>> {
- using type = Out;
- };
- template <typename Out, typename Rest, template <typename ...> class Op>
- struct MetaFilter<Out, Rest, Op,
- std::enable_if_t<Op<typename Rest::head>::value>>
- : MetaFilter<typename Out::template MetaPushBack<typename Rest::head>,
- typename Rest::tail, Op> {};
- template <typename Out, typename Rest, template <typename ...> class Op>
- struct MetaFilter<Out, Rest, Op,
- std::enable_if_t<!Op<typename Rest::head>::value>>
- : MetaFilter<Out, typename Rest::tail, Op> {};
- template <typename Out, typename Rest, template <typename ...> class Op,
- typename Enable = void>
- struct MetaFlatmap;
- template <typename Out, typename Rest, template <typename ...> class Op>
- struct MetaFlatmap<Out, Rest, Op,
- std::enable_if_t<Rest::length == 0>> {
- using type = Out;
- };
- template <typename Out, typename Rest, template <typename ...> class Op>
- struct MetaFlatmap<Out, Rest, Op,
- std::enable_if_t<Rest::length != 0>>
- : MetaFlatmap<typename Out::template MetaAppend<
- typename Op<typename Rest::head>::type>,
- typename Rest::tail, Op> {};
- template <typename LeftTL, typename RightTL>
- struct MetaCartesianProduct {
- template <typename LeftT>
- struct LeftHelper {
- template <typename RightT>
- struct RightHelper {
- using type = TypeList<LeftT, RightT>;
- };
- using type = typename RightTL::template MetaApply<RightHelper>;
- };
- using type = typename LeftTL::template MetaFlatmap<LeftHelper>;
- };
- template <typename ...Ts>
- class TypeListBase {
- public:
- // Members
- static constexpr std::size_t length = sizeof...(Ts);
- using type = TypeList<Ts...>;
- using self = type;
- // Meta methods
- template <typename Type>
- using MetaPushBack = TypeList<Ts..., Type>;
- template <std::size_t n>
- using MetaTake = typename MetaTake<self, EmptyList, n>::type;
- template <std::size_t n>
- using MetaSkip = typename MetaSkip<self, n>::type;
- template <typename OtherTypeList>
- using MetaAppend = typename MetaAppend<self, OtherTypeList>::type;
- template <template <typename ...> class Op>
- using MetaApply = TypeList<typename Op<Ts>::type...>;
- template <template <typename ...> class Op>
- using MetaFilter = typename MetaFilter<EmptyList, self, Op>::type;
- template <template <typename ...> class Op>
- using MetaFlatmap = typename MetaFlatmap<EmptyList, self, Op>::type;
- template <typename TL>
- using MetaCartesianProduct = typename MetaCartesianProduct<self, TL>::type;
- // Static methods
- template <typename Functor>
- static inline void ForEach(const Functor &functor) {
- ForEachInternal<length == 0>(functor);
- }
- private:
- template <bool kEmpty, typename Functor,
- std::enable_if_t<!kEmpty> * = nullptr>
- static inline void ForEachInternal(const Functor &functor) {
- functor(MetaTake<1>());
- MetaSkip<1>::ForEach(functor);
- }
- template <bool kEmpty, typename Functor,
- std::enable_if_t<kEmpty> * = nullptr>
- static inline void ForEachInternal(const Functor &functor) { /* No-op */ }
- };
- } // namespace meta_internal
- template <typename T, typename ...Ts>
- class TypeList<T, Ts...> : public meta_internal::TypeListBase<T, Ts...> {
- public:
- using head = T;
- using tail = TypeList<Ts...>;
- };
- template <>
- class TypeList<> : public meta_internal::TypeListBase<> {};
- ////////////////////////////////////////////////////////////////////////////////
- //////////////////////// 带类型检查的Base::Instantiate实现 ////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- using SubclassList = TypeList<DerivedExample,
- AnotherExample /* ... 在这里注册所有的子类 ... */>;
- template <typename SubclassWithArgList>
- struct IsConstructibleWithArgTypes;
- template <typename Subclass, typename... ArgTypes>
- struct IsConstructibleWithArgTypes<TypeList<Subclass, TypeList<ArgTypes...>>> {
- static constexpr bool value =
- std::is_constructible<Subclass, ArgTypes...>::type::value;
- };
- template <typename... Ts>
- Base* Base::Instantiate(const std::string& name, Ts&&... args) {
- // 在编译时枚举所有SubclassList中的类型(也就是Base的子类)
- // 并筛选出对于变长参数类型Ts...拥有合法构造函数的子类,放在Candidates里
- using Candidates =
- typename SubclassList::MetaCartesianProduct<TypeList<TypeList<Ts...>>>
- ::template MetaFilter<IsConstructibleWithArgTypes>;
- // 如果没有任何一个子类可以接收Ts...类型,那么直接可以在编译时报错
- static_assert(Candidates::length != 0,
- "Compile-time error: no matching constructor for the "
- "specified arguments");
- // 否则,只有在运行时看到name的值的时候,我们才能知道构造参数是否是对应name的那个子类的
- Base* instance = nullptr;
- // 枚举Candidates里的所有子类,如果其名字和name一致的话,那么由前面的筛选可知参数一定是合法的
- Candidates::ForEach([&](auto e) {
- using Subclass = typename decltype(e)::head::head;
- if (name != Subclass::GetName()) {
- return;
- }
- if (instance != nullptr) {
- std::cout << "Runtime error: duplicated subclass name '"
- << name << "'\n";
- }
- instance = new Subclass(std::forward<Ts>(args)...);
- });
- if (instance == nullptr) {
- std::cout << "Runtime error: no matching constructor for "
- << "initialization of '" << name << "'\n";
- }
- return instance;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////// 测试样例 ////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- int main(int argc, char *argv[]) {
- Base* first = Base::Instantiate("DerivedExample");
- // 输出:DerivedExample
- first->Run();
- Base* second = Base::Instantiate("AnotherExample", 123, "Hello world");
- // 输出:AnotherExample 123 Hello world
- second->Run();
- // 编译时错误:no matching constructor for the specified arguments
- // Base* third = Base::Instantiate("DerivedExample", 123);
- // 运行时报错:no matching constructor for initialization of 'AnotherExample'
- Base* fourth = Base::Instantiate("AnotherExample");
- // 输出:1
- std::cout << (fourth == nullptr) << "\n";
- return 0;
- }
复制代码 |
|