我在c ++中编写某种DI容器,如果可以在现代c ++中创建从一种类型到另一种类型的别名,我很好奇。 我基本上想要做的是能够通过它的别名接口调用实现构造函数。像这样:
di::Register<Interface, Impl>();
di::Resolve<Interface>(); // -> Impl should be resolved
问题是到目前为止我还没能在编译时找到对接口和Impl进行别名的方法。我可以使用RTTI做到这一点,但我真的不想使用它。它有可能吗?
答案 0 :(得分:1)
通过查看代码的界面,如果你有一个全局状态(我没有积极推荐)你应该侥幸逃脱:
using type_id_t = void(*)();
template<typename> void type_id() {}
struct di {
using create_function_t = void*(*)();
static std::unordered_map<type_id_t, create_function_t> types;
template<typename I, typename T>
static void Register() {
types.emplace(type_id<I>, []{
return static_cast<void*>(
static_cast<I*>(new T)
);
});
}
template<typename I>
static std::unique_ptr<I> Resolve() {
return std::unique_ptr<I>{static_cast<I*>(types[type_id<I>]())};
}
};
答案 1 :(得分:0)
问题是到目前为止我还没能在编译时找到对接口和Impl进行别名的方法。我可以使用RTTI做到这一点,但我真的不想使用它。它有可能吗?
假设我正确理解了你的目标,你可以用它来做到这一点。它看起来不像你在那里那么好:
http://stackoverflow.com/questions/4790721/c-type-registration-at-compile-time-trick
这个技巧归功于Matt Calabrese,他在a Boostcon talk in like 2011中描述了这一点。
据我所知,这个技巧符合标准,但你必须非常小心 - 如果你在一些头文件中开始注册然后在某些CPP文件中继续注册,你可能会导致ODR违规不小心。
我认为你最终会得到像
这样的宏REGISTER_PAIR( interface, impl );
然后你会有一些类型别名,例如
get_registered_impl_t<interface>
解析为impl
。
在示例中,它们展示了如何制作随时间累积的类型列表。在你的情况下,它将是一个类型级“对”的列表,你可以通过线性扫描搜索它。您可以尝试使用花哨的编译时映射数据结构,但在大多数情况下,它是无意义的,因为线性扫描将足够快,而且,您可以制作的列表长度受编译器的最大模板实例化深度的限制,通常像100或200或其他东西。如果你需要更大的列表,你可以使用一些技巧,但我不会在这里详述。