2017-09-25 37 views
3

我在C++中编写了一些DI容器,我很好奇它是否可以在现代C++中创建从一种类型到另一种类型的别名。 我基本上想要做的是能够通过它的别名接口调用实现构造函数。像这样:创建一个别名到另一个类型

di::Register<Interface, Impl>(); 
di::Resolve<Interface>(); // -> Impl should be resolved 

的问题是,我已经无法找到到目前为止办法别名接口并实现了一套在编译的时候。我可以使用RTTI来做到这一点,但我真的不想使用它。它有可能吗?

+0

你可能通过诸如[\ [Boost \] .DI](https://github.com/boost-experimental/di)之类的东西读取乐趣。 – chris

+0

我在[DI容器库](https://github.com/gracicot/kangaru/wiki/03.-Override-Services#default-service-type)中使用'kgr :: Default'做了一些非常类似的事情 –

+0

@GuillaumeRacicot是的,但我不想在这种情况下使用继承,我认为它使界面非常庞大。 – s0nicYouth

回答

0

问题是我目前还没有能够在编译时找到别名Interface和Impl的方法。我可以使用RTTI来做到这一点,但我真的不想使用它。它有可能吗?

假设我正确理解了你的目标,你可以使用这个技巧来做到这一点。它不会看起来像你一样,你有什么有:

http://stackoverflow.com/questions/4790721/c-type-registration-at-compile-time-trick

这一招是由于马特卡拉布雷斯,他在a Boostcon talk in like 2011描述它。

据我所知,此技巧符合标准,但您必须非常小心 - 如果您确实在某些头文件中开始注册,然后在某些CPP文件中继续注册,则可能会导致ODR违例你是不小心的。

我想你最终会像

REGISTER_PAIR(interface, impl); 

一些宏,然后你会有些类型的别名,如

get_registered_impl_t<interface> 

它解析为impl

在这个例子中,他们展示了如何制作一段时间内积累的类型列表。在你的情况下,它将是一个类型级别的“对”列表,你可以通过线性扫描进行搜索。你可以尝试使用一个花哨的编译时地图数据结构,但是在大多数情况下,它的线性扫描没有意义,因为它的速度足够快,而且你可以创建的列表长度受编译器最大模板实例化深度的限制,通常像100或200或其他东西。如果你需要更大的列表,你可以使用一些技巧,但我不会在这里详细说明。

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>]())}; 
    } 
}; 

Live example

+0

是的,你是对的。我要在这里使用全局状态。尽管我的目标是实现非常接近dagger2的东西。感谢您的snipet,但正如我所提到的,我正在寻找一种在编译时实现它的方法。就像使用I = T一样。但是您的解决方案无论如何都是RTTI的好替代品。 – s0nicYouth

+0

我不建议使用全局状态。特别是对于DI。这段代码在没有任何全局状态的情况下使用非常简单。只需删除所有静态关键字和瞧。 –

+0

我明白了。但对我而言,这里的全球状态不是问题。我的问题的主要目标是找到在编译时绑定类型的方式。即使我删除全局状态,不幸的是你的解决方案不会这样做。 – s0nicYouth