Use typedef within struct for naming and indexing text commands

前端 未结 2 487
甜味超标
甜味超标 2021-01-15 02:34

I am working with a simple command line application that takes in ASCI text and interprets it as a command.

I have attempted to minimize the redundancy in this appli

相关标签:
2条回答
  • 2021-01-15 03:11

    Question:

    Is there any method using the C preprocessor that would allow me to create a macro creates the "command" struct (with string and int members), and auto-numbers the int value (command_idx) as I add more commands via the COMMAND() macro?

    Yes, and since you have tagged the question also as C++:

    #include <iostream>
    #include <map>
    #include <string>
    using namespace std;
    
    map< string, int >     commands;
    
    bool register_cmd( int id, string const& name )
    {
        commands[name] = id;
        return true;
    }
    
    #define COMMAND( name ) \
        int const name ## _cmd = __LINE__; \
        bool const name ## _reg = register_cmd( name ## _cmd, #name )
    
    COMMAND( exit );
    COMMAND( help );
    COMMAND( do_stuff );
    
    int cmd_id( string const& name )
    {
        auto const it = commands.find( name );
        return (it == commands.end()? -1 : it->second );
    }
    
    int main()
    {
        for( auto it = commands.begin();  it != commands.end();  ++it )
        {
            cout << it->first << " => " << it->second << endl;
        }
    
        cout << "Gimme a command, please: ";
        string cmd;  getline( cin, cmd );
        switch( cmd_id( cmd ) )
        {
        case exit_cmd:
            cout << "You typed an EXIT command, which has id " << exit_cmd << endl;
            break;
        default:
            cout << "Hey, why not try an 'exit' command?" << endl;
        }
    }
    

    I just used map instead of fancy new C++11 hash table because map works with older compilers and no real need for shaving nano-seconds here.

    Cheers & hth.,

    0 讨论(0)
  • 2021-01-15 03:13

    You can use macro redefinition to achieve this. First, you create a file that simply lists your commands called commands.inc:

    COMMAND(quit)
    COMMAND(help)
    ...
    

    Then, in your C source you can #include "commands.inc" multiple times, with different definitions of COMMAND() in effect to control how it works. For example:

    struct command
    {
       char *name;
       int command_idx;
    };
    
    #define COMMAND(NAME) CMD_ ## NAME,
    
    enum command_enum {
    #include "commands.inc"
    };
    
    #undef COMMAND
    
    #define COMMAND(NAME) { #NAME, CMD_ ## NAME },
    
    struct command commands[] =
    {
    #include "commands.inc"
    };
    
    #undef COMMAND
    

    (Note that this particular example relies on a C99 improvement that allows a trailing , at the end of the lists in the enum declaration and compound initialiser - you can easily work around that in C89 by adding a dummy entry at the end).

    0 讨论(0)
提交回复
热议问题