2017-04-18 40 views
0

我需要(或者更好的是,我有机会)重构一些代码以使其更清洁。如何在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

我的建议:

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

当然!我真的忽视了它! 'assignFromValue'的模板根本不需要.. – btbbass

+0

试过了一下,我非常喜欢这个方法。开始重构类之外的移动方法,这可能是一个好方法(我真的讨厌凌乱的类)! – btbbass

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); 
} 
+0

@RSahu你能解释一下吗?我可以看到它没有问题。 –

+0

@RSahu啊误解了原始代码。将更新。 –

+0

@RSahu修,谢谢。我已经在两个代码路径中读取了'IsNumber()'作为前提条件。 –