Home > Enterprise >  How to remove this kind of duplication (for cycle over types)?
How to remove this kind of duplication (for cycle over types)?

Time:06-11

I have code like this:

template<class Command>
void registerCmd() {
    Command x{};
    // do something with x...
}

namespace Cmd
{
    struct GET { /* some methods */ };
    struct GETSET { /* some methods */ };
    struct DEL { /* some methods */ };

    void registerCommands() {
        registerCmd<GET>();
        registerCmd<GETSET>();
        registerCmd<DEL>();
    }
}

I like how the code turns out. I was wondering if there is a way this code to be changed to something like this:

namespace Cmd 
{
    void register() {
        // this does not compile
        for (TYPE in{ GET, GETSET, DEL })
            registerCmd<TYPE>();
    }
}

May be with variadic templates?

CodePudding user response:

You can not have a collection of different types in a range based for loop, unless you have them in an array of std::variant, std::anyor such types.

If you're willing to make the registerCommands template function which has variadic template arguments as template parameter, with the help of fold expression (since ) you might do (provided that the number types are known at compile time):

template<typename... Types>
void registerCommands() {
    (registerCmd<Types>(), ...);
}

and function calling

Cmd::registerCommands<Cmd::DEL, Cmd::GETSET, Cmd::GETSET>();

Live Demo

CodePudding user response:

Clarification, probably will help others.

It turns out, the template template class is like this:

template<
    template<class, class>  class Cmd,
    class Protocol,
    class DBAdapter,
    class Storage,
    class Map
>
void registerCmd(Storage &s, Map &m){
//...
}

I still was able to do it with fold, in following way:

template<
    class Protocol,
    class DBAdapter,
    class Storage,
    class Map,
    template<class, class>  typename... Commands
>
void registerCommands(Storage &s, Map &m){
    ( registerCmd<Commands, Protocol, DBAdapter>(s, m), ... );
}

and here is how I call it:

    struct SET { /* some methods */ };
    struct SETEX { /* some methods */ };
    struct SETNX { /* some methods */ };
    struct DEL { /* some methods */ };
    struct GETSET { /* some methods */ };
    struct EXPIRE { /* some methods */ };

    registerCommands<Protocol, DBAdapter, Storage, Map,
        SET ,
        SETEX   ,
        SETNX   ,
        DEL ,
        GETSET  ,
        EXPIRE
    >(s, m);

Here are link to the files:

  • Related