C++知识点(6)_表驱动法替代if-else或switch语句

通常来说,出现不同数据格式转换的场景,比如给定一个整数,将它与每周的星期名称映射,通常会采用if-else或switch语句,但是这种语句存在两个问题
(1)代码太长,逻辑重复冗余,复杂度高
(2)可维护性低,耦合性强,每新增一个流程分支,就要在函数代码中新添加一个判断语句。
这里介绍一种通用的表驱动实现方法替代以上方式。
要实现一个通用的表驱动模式需要解决两个问题:
(1)如何在表中注册不同类型的执行函数?
(2)在表中找到对应的执行函数之后如何调用执行函数。由于每个函数的形参不尽相同,如何用统一的方式调用?
解决思路:
问题1:可以使用boost::Any解决
问题2:可以采用C++11的可变模板参数解决
通用的表驱动C++11实现支持各种类型的key,执行函数支持普通函数、函数对象、lamda表达式和成员函数。
.hpp文件

#ifndef TABLE_DRIVER_APPROACH_HPP_
#define TABLE_DRIVER_APPROACH_HPP_
#include<iostream>
#include<array>
#include<map>
#include<functional>
#include<type_traits>
#include<boost/any.hpp>
#include<typeinfo>
template<typename Key>
class TableDriver
{
public:
    template<typename... Args,typename Func>
    void Register(const Key& key,Func &&func)
    {
        typedef typename std::result_of<Func(Args...)>::type rettype;
        auto f=std::function<rettype(Args && ...)>([=](Args &&... args){return func(std::forward<Args>(args)...); });
        m_map[key]=f;
    }

    template<typename R=void,typename... Args>
    R Execute(const Key& key,Args &&... args) 
    {
        auto it=m_map.find(key);
        if(it==m_map.end())
        {
            return R();
        }
        auto f=boost::any_cast<std::function<R(Args && ...)> >(it->second);
        return f(std::forward<Args>(args)...);
    }

    template<typename R=void> //无参数
    R Execute(const Key& key)
    {
         auto it=m_map.find(key);
         if(it==m_map.end())
         {
             return R();
         }
         auto f=boost::any_cast<std::function<R()> >(it->second);
         return f();
    }
private:
    std::map<Key,boost::any> m_map;
};

#endif

测试代码:

#include"TableDriveApproach.hpp"
TableDriver<int> dv;
const std::string GetDayName(const int& day)
{
    return dv.Execute<std::string>(day);
}
int main()
{
    dv.Register(0,[]()->std::string{return "星期日";});
    dv.Register(1,[]()->std::string{return "星期一";});
    dv.Register(2,[]()->std::string{return "星期二";});
    dv.Register(3,[]()->std::string{return "星期三";});
    dv.Register(4,[]()->std::string{return "星期四";});
    dv.Register(5,[]()->std::string{return "星期五";});
    dv.Register(6,[]()->std::string{return "星期六";});
    int day=3;
    std::cout<<GetDayName(day)<<std::endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章