s0nicYouth
s0nicYouth

Reputation: 500

Create an alias from one type to another

I'm writing some kind of DI container in c++ and I'm curious if it's possible to create aliases from one type to another in modern c++. What I basicly want to do is to be able to call implementation constructor by it's aliased interface. Like so:

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

The problem is that I've not been able to find the way to alias Interface and Impl in compile time so far. I can do this using RTTI but I really don't want to use it. Is it possible at all?

Upvotes: 3

Views: 176

Answers (2)

Guillaume Racicot
Guillaume Racicot

Reputation: 41760

By looking at the interface of your code, if you have a global state (which I don't actively recommend) you should get away with that:

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

Upvotes: 1

Chris Beck
Chris Beck

Reputation: 16204

The problem is that I've not been able to find the way to alias Interface and Impl in compile time so far. I can do this using RTTI but I really don't want to use it. Is it possible at all?

There is a trick you can use to do this, assuming I understood your goal correctly. It won't look as nice as what you have there:

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

This trick was attributed to Matt Calabrese, he described it in a Boostcon talk in like 2011.

To the best of my knowledge this trick is standards-conforming, but you must be very careful -- if you do start the registration in some header files and then continue it in some CPP files you may cause an ODR violation if you are careless.

I think you would end up with some macro like

REGISTER_PAIR( interface, impl );

and then you would have some type-alias, e.g.

get_registered_impl_t<interface>

which resolves to impl.

In the example they show how to make a list of types that is accumulated over time. In your case it would be a list of type-level "pairs" and you could search it by doing linear scan. You could try to use a fancy compile-time map data structure, but in most cases its pointless since linear scan will be fast enough, and also, the length of the list you can make is bounded by the maximum template instantiation depth of your compiler, which is typically like 100 or 200 or something. If you need larger lists there are some tricks you can use but I won't detail here.

Upvotes: 0

Related Questions