Arbitrary order of the template initialization list

    I think many who work with templates are familiar with the following situation. We have some template class with a bunch of template parameters

    struct deferred;
    struct deadline;
    struct disable;
    template
    struct some_container
    

    Let it be some kind of delayed task execution interface (active queue). And we want to expand its functionality by adding deferred execution and deadlines. But we do not want all of this to be immediately turned on, but we want to be able to assemble the necessary configuration for your needs. The problem with such templates (which have a lot of parameters and almost all already have a default value) is that in order to redefine, say, the last parameter, we need to specify all that stand before it.

    typedef some_container deadline_container;
    
    А хотелось бы 
    
    typedef some_container deadline_container;
    

    Better yet, even the order of the assignment does not matter and the next two are equivalent

    typedef some_container full_container1;
    typedef some_container full_container1;
    

    But we are well aware that as soon as we change the two parameters, it will turn out completely wrong with what we expected (this is not a tuple for you where the order does not
    matter ) I think many people have already thought that all this can be achieved by adding a layer between our type and by the user for whom to write all possible specializations. If you have only 2 template parameters, then yes, if 3 is already difficult, and if 4, 5 is added, then write is gone. And as a rule, adding a new parameter leads to redoing all previous specializations (since in a specialization we cannot increase the number of template parameters, but we can only reduce them).
    If you are interested, I ask for a cut, I will show you how to achieve this

    But first, a bit of tar. Template types are good because the user can parameterize them with different types, including their own. The method that I want to show does not allow you to specialize a template with an arbitrary type. Those. for example, you define your deadline_super type which is comparable to the deadline type, then you can substitute it into the template specialization

    typedef some_container

    But you cannot use this type in the mechanism that will allow you to specialize the template in an arbitrary form. Perhaps this is the only serious limitation. Given this aspect, it becomes clear that this mechanism is convenient to use when writing modular components, rather than extensible or polymorphic.
    The entire implementation is based on such a boost component as mpl :: set . I will not talk much about what boost :: mpl is , I’ll just say that mpl :: set allows you to create a container similar to std :: set but at the compilation stage and consisting of types.
    The first thing we need is a way to check the list of types for the type we need, and return some default value (struct disable) otherwise

    template 
    struct get_plugin_impl;
    template 
    struct get_plugin_impl
    {
        typedef disable_plugin type;
    };
    template 
    struct get_plugin_impl
    {
        typedef Plugin type;
    };
    template 
    struct get_plugin
    {
        typedef typename get_plugin_impl::type>::type type;
    };
    

    This will allow us to find out from the list of types whether the type we need was specified and if not, then use the default value. As you can see, this code depends on only one type that participates in the parameterization of the final structure (and reports that we are not using this particular type), so when adding new template types, this code will not change.
    In the next step, we define all types that are used in the final template

    template 
    struct get_plugins
    {
        typedef typename get_plugin::type deferred;
        typedef typename get_plugin::type deadline;
    };
    

    And this is the place that will change when adding new template parameters. But this is extremely easy, and no 2 ^ n combinations need to be listed.
    Next, we introduce a layer between the final template type and the user

    template
    struct container
    {
        typedef boost::mpl::set plugin_list;
        typedef get_plugins plugs;
        typedef typename plugs::deferred deferred;
        typedef typename plugs::deadline deadline;
        typedef some_container type; 
    };
    

    Namely, it allows us to abstract from the number and order of specifying template parameters. In fact, it combines all those (2 ^ n + K) specializations that we would have to write for a different number of given template parameters and their order.

    Returning to our template type, I will show you how it works

    #define static_type(name) \
        static const std::string& type() \
        { \
            static std::string type_(name); \
            return type_; \
        } \
    struct deferred_plugin
    { static_type("deferred"); };
    struct deadline_plugin
    { static_type("deadline"); };
    struct disable_plugin
    { static_type("disable"); };
    template
    struct some_container
    {
        static const std::string& type()
        {
            static std::string type_("some_container<" + 
                                        Deferred::type() + ", " +
                                        Deadline::type() + ">");
            return type_;
        }
    };
    

    Using

       cout << container::type::type() << std::endl;
       cout << container::type::type() << std::endl;
       cout << container::type::type() << std::endl;
       cout << container::type::type() << std::endl;
       cout << container::type::type() << std::endl;
    

    Exhaust

    some_container
    some_container
    some_container
    some_container
    some_container

    Please note that the order of specialization is saved in the right form, regardless of the order in which the types were specified when instantiating the template.

    That's all, I hope this helps someone to make the code more beautiful and accurate.
    Source: git

    Also popular now: