如何为管理结构数组的类创建模板

时间:2018-12-08 11:22:54

标签: c++ templates arduino

我想创建一个可重用的类,该类描述一个结构数组,其中包含一个指向类中方法的指针。该类还包含“执行”和“显示”方法。我认为execute方法也需要模板化,但是我仍在努力学习模板。

挑战:如何将此类转化为模板并提供 几个使用模板的例子?

该类结合了typedefstruct和我想在多个类之间共享的方法。每个实例将具有自己的struct数组,每个数组都包含一个指向字符串的指针和一个指向类中方法的指针。

我想使用模板,以便它支持同一struct的数组的多个实例,但是内容不同。

此代码表示的是一种实现简单命令语言的方法,该方法将两个代码(sel和act)传递给execute方法,该方法在数组中搜索两个代码的匹配项,然后分派相应的方法。

此代码还包括模板中也需要包含的两种方法:show(遍历数组并为每个命令提供帮助信息)和execute(调用适当的函数)。

class Commands {
public:
    typedef void ( Commands::*FunctionPointer )( char, char );


    struct command {
        char sel;
        char act;
        char const *desc;
        FunctionPointer funcPtr;
    };


    command myCommands [2] = {
        command { 'a','?',"Pass a and ? to foo", &Commands::foo },
        command { 'b','x',"Pass b and x to bar", &Commands::bar },
    };


    int cmdSize = sizeof ( myCommands ) / sizeof ( myCommands [0] );


    void foo ( char sel, char act ) {
        show ( { sel }, { act } );
    }


    void bar ( char sel, char act ) {
        show ( { sel }, { act } );
    }


    void show ( char sel, char act ) {
        //  sel and act are ignored vy this method
        for (int i = 0; i < cmdSize; i++) {
            Serial.print ( "SEL = " );
            Serial.print ( myCommands [i].sel );
            if (sel == myCommands [i].sel) Serial.print ( '*' );
            Serial.print ( ", ACT=" );
            Serial.print ( myCommands [i].act );
            if (act == myCommands [i].act) Serial.print ( '*' );
            Serial.print ( ' ' );
            Serial.println ( myCommands [i].desc );
        }
    }


    void execute ( char sel, char act ) {
        for (int i = 0; i < cmdSize; i++) {
            if (myCommands [i].sel == sel && myCommands [i].act == act) {
                Serial.println ( myCommands [i].desc );
                ( this->*myCommands [i].funcPtr )( sel, act );
                return;
            }
        }
        Serial.print ( F ( "Unknown SEL/ACT Pair:" ) );
        Serial.print ( sel );
        Serial.print ( '/' );
        Serial.println ( act );
    }
};

还有Arduino Sketch:

#include "Commands.h"

Commands cmd;


void setup() {
    Serial.begin ( 115200 );
    cmd.show ( '?', '?' );
    Serial.println ( "EXECUTING:" );
    cmd.execute ( 'a', '?' );
    cmd.execute ( 'b', '?' );
    cmd.execute ( 'b', 'x' );
    Serial.println ( "DONE" );
}


void loop(){}

最后,是执行草图的输出:

SEL = a, ACT=?* Pass a and ? to foo
SEL = b, ACT=x Pass b and x to bar
EXECUTING:
Pass a and ? to foo
SEL = a*, ACT=?* Pass a and ? to foo
SEL = b, ACT=x Pass b and x to bar
Unknown SEL/ACT Pair:b/?
Pass b and x to bar
SEL = a, ACT=? Pass a and ? to foo
SEL = b*, ACT=x* Pass b and x to bar
DONE

1 个答案:

答案 0 :(得分:0)

  

我想创建一个可重用的类来描述结构数组   其中包含指向类中方法的指针。上课还   包含“执行”和“显示”方法。我认为执行方法   也需要模板化,但我仍在努力学习   模板。

我不得不说我不明白你想确切地做什么。但是,查看您的代码似乎要使用std::map而不是数组(因此您可以将“命令”映射到函数指针)。如果要调用的所有方法都具有相同的签名(void(char,char)),则无需过多处理模板。相反,我建议您看看std::function和lambda。

#include <iostream>
#include <string>
#include <map>
struct command_center {
    using command = std::string;
    using comment = std::string;    
    using action = std::function< void(char,char) >;
    std::map< command,action > action_commands;
    void register_action_command( command c, action a) { 
        action_commands[c] = a; 
    }
    void execute( command c, char a,char b) { 
        auto it = action_commands.find(c);
        if (it == action_commands.end()) {
            std::cout << "command not found: " << c << "\n";
            return;
        }
        it->second(a,b);
    }
};

struct foo{
    void bar(char a,char b) { std::cout << a << b << " foo\n";}
};

int main(){
    command_center cc;
    cc.register_action_command("test1",[](char a,char b){ std::cout << a << b << "\n";});
    cc.execute("test1",'a','b');
    cc.execute("unknown",'a','b');
    foo f;
    cc.register_action_command("foobar",[&f](char a,char b){ f.bar(a,b); });
    cc.execute("foobar",'a','b');
}

输出:

ab
command not found: unknown
ab foo

请注意,当您将自己限制为固定签名(即类型的函数指针)时,它可以在没有lamdbas和std::function的情况下工作

using my_function_pointer_type = void(*)(char,char);

但是,通过将lambda传递给std::function,您可以包装带有正确签名的任何可调用对象,并将其注册以供以后调用(无论它是自由函数还是示例中的某些成员方法)。

PS:可以对上面的command_center进行参数设置,以使用具有不同签名的函数指针。只是在写完这个答案后,我才意识到问题可能就是这个问题吗?