如何在C ++中使用模板重构方法

时间:2017-04-18 15:22:54

标签: c++

我需要(或者更好,我有机会)重构一些代码以使其更清晰。

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

这是我的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();
}

有没有更聪明的方法呢?

2 个答案:

答案 0 :(得分:2)

我的建议:

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

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

  3. 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();
    }
    

答案 1 :(得分:2)

我想我是用tag-dispatched转换器对象来做的:

#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);
}