简体   繁体   English

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

[英]How to refactor method using template in C++

I am in need to (or better, I have the chance to) refactor some code in order to make it cleaner. 我需要(或者更好的是,我有机会)重构一些代码以使其更整洁。

I would like to use some template, as I think this is a good candidate, in order to reduce the code duplication. 我想使用一些模板,因为我认为这是一个不错的选择,以减少代码重复。

Here is my hpp 这是我的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;
};

And here is the implementation for the the initMember methods: 这是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();
  }
}

I was thinking about writing something like 我正在考虑写类似

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

Is there any clewer way to do that ? 有什么明智的方法吗?

My suggestions: 我的建议:

  1. You don't need to make assignFromValue member functions. 您不需要制作assignFromValue成员函数。 If you can implement functionality using non-member functions, you should prefer non-member functions. 如果可以使用非成员函数实现功能,则应首选非成员函数。 See How Non-Member Functions Improve Encapsulation and How Non-Member Functions Improve Encapsulation . 请参阅非成员函数 如何 改善封装非成员函数如何改善封装

  2. You don't need to make assignFromValue function templates. 您无需制作assignFromValue函数模板。 They can be simple overloads. 它们可以是简单的重载。


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

I think I'd do it with a tag-dispatched converter object: 我想我可以使用分派标签的转换器对象来做到这一点:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM