从一种类型到另一种类型创建别名

时间:2017-09-25 16:25:23

标签: c++ c++11 metaprogramming

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

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

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

2 个答案:

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

Live example

答案 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或其他东西。如果你需要更大的列表,你可以使用一些技巧,但我不会在这里详述。