【问题标题】:How to refactor method using template in C++如何在 C++ 中使用模板重构方法
【发布时间】:2017-04-18 15:22:54
【问题描述】:

我需要(或者更好的是,我有机会)重构一些代码以使其更简洁。

我想使用一些模板,因为我认为这是一个很好的候选,以减少代码重复。

这是我的 hpp

class Monetary
{
 public:
  Monetary();
  Monetary(const rapidjson::Value& iMonetary);
  virtual ~Monetary();

  [...cut...]

 private:

  static void initMember(const rapidjson::Value& iMonetary, const char* iName, int& oMember);
  static void initMember(const rapidjson::Value& iMonetary, const char* iName, std::string& oMember);


 private:
  int _amount;
  int _decimal_place;
  std::string _currency;
  std::string _type;
};

这是 initMember 方法的实现:

static void Monetary::initMember(const rapidjson::Value& iMonetary, const char* iName, int& oMember)
{
  rapidjson::Value::ConstMemberIterator aIterator;
  aIterator = iMonetary.FindMember(iName);
  if ( aIterator != iMonetary.MemberEnd() &&
      aIterator->value.IsNumber() )
  {
    oMember = iMonetary[iName].GetInt();
  }
}

static void Monetary::initMember(const rapidjson::Value& iMonetary, const char* iName, std::string& oMember)
{
  rapidjson::Value::ConstMemberIterator aIterator;
  aIterator = iMonetary.FindMember(iName);
  if ( aIterator != iMonetary.MemberEnd() &&
      aIterator->value.IsNumber() )
  {
    oMember = iMonetary[iName].GetString();
  }
}

我正在考虑写类似的东西

template<typename T>
void Monetary::initMember(const rapidjson::Value& iMonetary, const char* iName, T& oMember)
{
  rapidjson::Value::ConstMemberIterator aIterator;
  aIterator = iMonetary.FindMember(iName);
  if (aIterator == iMonetary.MemberEnd())
  {
    return;
    //throw monetaryException
  }
  assignFromValue(iMonetary[iName], oMember);
}
template<>
void Monetary::assignFromValue<int>(const rapidjson::Value& iValue, int& oMember)
{
  if (!iValue.IsNumber())
  {
    return;
    //throw monetaryException
  }
  oMember = iValue.GetInt();
}
template<>
void Monetary::assignFromValue<std::string>(const rapidjson::Value& iValue, std::string& oMember)
{
  if (!iValue.IsString())
  {
    return;
    //throw monetaryException
  }
  oMember = iValue.GetString();
}

有什么更简洁的方法吗?

【问题讨论】:

    标签: c++


    【解决方案1】:

    我的建议:

    1. 您不需要创建assignFromValue 成员函数。如果您可以使用非成员函数来实现功能,那么您应该更喜欢非成员函数。请参阅How Non-Member Functions Improve EncapsulationHow Non-Member Functions Improve Encapsulation

    2. 您不需要制作assignFromValue 函数模板。它们可以是简单的重载。


    void assignFromValue(const rapidjson::Value& iValue,
                         int& oMember)
    {
      if (!iValue.IsNumber())
      {
        return;
        //throw monetaryException
      }
      oMember = iValue.GetInt();
    }
    
    void assignFromValue(const rapidjson::Value& iValue,
                         std::string& oMember)
    {
      if (!iValue.IsString())
      {
        return;
        //throw monetaryException
      }
      oMember = iValue.GetString();
    }
    

    【讨论】:

    • 当然!我真的忽略了! assignFromValue 的模板根本不需要..
    • 试了一下,我真的很喜欢这种方法。开始在课堂外重构移动方法,这可能是个好方法(我真的很讨厌混乱的课堂)!
    【解决方案2】:

    我想我会用标签调度的转换器对象来做:

    #include <string>
    #include <type_traits>
    #include <stdexcept>
    
    // simulate your value class
    struct Value
    {
        bool IsNumber() const;
        bool IsString() const;
        std::string getString() const;
        int getInt() const;
    };
    
    
    // a tag type for easy tag dispatching
    template<class Type> struct tag {};
    
    
    // a converter object contains all rules and conversion sequences
    struct ValueConverter
    {
        std::string operator()(tag<std::string>, const Value& v) const
        {
            if (not v.IsString()) throw std::invalid_argument("not a string");
            return v.getString();
        }
    
        int operator()(tag<int>, const Value& v) const
        {
            if (not v.IsNumber()) throw std::invalid_argument("not a number");
            return v.getInt();
        }
    };
    
    // write the member once
    template<class Target>
    void initMember(const Value& iMonetary, const char* iName, Target& oMember)
    {
        using target_type = std::decay_t<Target>;
        auto converter = ValueConverter();
        oMember = converter(tag<target_type>(), iMonetary);
    }
    

    【讨论】:

    • @RSahu 你能解释一下吗?我看不出有什么问题。
    • @RSahu 已修复,谢谢。我已经阅读了 IsNumber() 作为两个代码路径中的前提条件。
    猜你喜欢
    • 1970-01-01
    • 2015-03-20
    • 2013-03-07
    • 1970-01-01
    • 2019-01-02
    • 2012-12-20
    • 1970-01-01
    • 2020-05-23
    • 1970-01-01
    相关资源
    最近更新 更多