2017-04-18 24 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()'作爲前提條件。 –

相關問題