2011-09-14 47 views
3

我有兩個系統,我需要映射之間的類型 - 源數據字段,可以是數字,字符或字符串,都存儲爲字符串對象;目標系統需要爲每個數據字段的基礎類型使用不同的數據類型,並且我需要動態執行此映射。因此,基本上,對於每個數據字段,我都有實際的字段's'和底層數據類型'type',並且我試圖根據'type'轉換爲類型'dest' 。我一直試圖使用模板和模板常量來破解可以做到這一點的東西,但沒有運氣。基於不同的模板參數轉換爲不同的數據類型

目前的嘗試我有如下,但這並不因爲編譯爲衝突的返回類型:

template<class CLASSTYPE, int CLASSID> 
CLASSTYPE returnDifferentTypes() 
{ 
using namespace std; 

if (CLASSID == 1) // 1 = "string" 
    return std::string("returned string"); 

if (CLASSID == 2) // 2 = int 
    return 123; 

if (CLASSID == 3) // 3 = double 
    return 123.123; 
} 

所以我一直呼籲像

string mapped = returnDifferentTypes<string, 1>() 

or 
    int mapped = returnDifferentTypes<int, 2>() 

誰能推薦一個更聰明的清潔方式來做到這一點?理想情況下,我試圖返回適當的返回類型,只需要一個代表類型的字符串來映射它。提前致謝。

回答

2

如果您可以靜態識別ID,那麼模板pecialization可能更好的是if-s的網絡。

template<int id> 
struct multireturn; // not defined 

template<> 
struct multireturn<1> 
{ 
    typedef std::string return_type; 
    return_type operator()() { return "string"; } 
}; 

template<> 
struct multireturn<2> 
{ 
    typedef int return_type; 
    return_type operator()() { return 12; } 
}; 

template<> 
struct multireturn<3> 
{ 
    typedef double return_type; 
    return_type operator()() { return 12.3; } 
}; 

///call like this 
astring = multireturn<1>()() 
aint = multireturn<2>()() 
adouble = multireturn<3>()() 

同樣,你可以使用函數重載:

enum ret_string_t { ret_string; } 
enum ret_int_t { ret_int; } 
enum ret_ouble_t { ret_double; } 

std::string multireturn(ret_string_t) { return "string"; } 
int multireturn(ret_int_t) { return 12; } 
int multireturn(ret_double_t) { return 12.34; } 

/// call as: 
astring = multireturn(ret_string); 
aint= multireturn(ret_intg); 
adouble= multireturn(ret_double); 

或者 - 少正統,但仍working-

struct multireturn 
{ 
    operator std::string() { return "text"; } 
    operator int() { return 10; } 
    operator doble() { return 3.5; } 
}; 

///call as: 
astring = multireturn(); 
aint = multireturn(); 
adouble = multireturn(); 

當然,在所有的例子需要必須調整const正確性。

+0

+1哇,很多很好的選擇,我沒有想到。我認爲最後一個是最好的。 –

+0

+1這很好,我最終使用了整數特化方法,因爲我想關閉傳遞給函數的參數來確定返回類型。 – user944775

5

對於您的情況,CLASSID冗餘參數;所以省略它。

你可以簡單地專門方法returnDifferentTypes爲不同的數據類型的更清潔的方式。

template<class CLASSTYPE> 
CLASSTYPE returnDifferentTypes(); // undefined 

template<> 
std::string returnDifferentTypes<std::string>() { // for 'std::string' 
    return std::string("returned string"); 
} 
template<> 
int returnDifferentTypes<int>() { // for 'int' 
    return 123; 
} 
template<> 
double returnDifferentTypes<double>() { // for 'double' 
    return 123.123; 
} 

用法:

string mapped = returnDifferentTypes<string>(); 
int mapped = returnDifferentTypes<int>(); 
+1

+1。這是適當的解決方案。 – Nawaz

+0

我通常對功能模板進行專門化處理,可能是另一種設計可能會更好。 –

0

如果你真的想要,可以返回多種類型的功能,你正在尋找boost::variant或可能boost::any

但是,請至少花點時間考慮爲什麼你想要這種行爲,以及是否有一種替代方法可能不需要從同一函數返回多個不同類型。

0

如果要將數值或其他「iostream serializable」類型轉換爲字符串和字符串,可以使用boost::lexical_cast

1

除非您使用某種類型的Variant類而不是string來存儲所有內容,否則在代碼中的某處您需要有一種在類型之間進行選擇的分支形式。但是,轉換函數本身並不適合它。轉換函數只能返回一種類型。如果您嘗試在其中進行分支,則需要返回三種類型。再次,除非你使用變體或其他醜陋的黑客(例如void*),否則你永遠不會得到這個工作。

函數模板專業化在這裏不需要,假設你接受一個區分類型的分支。一個簡單的CvtTo函數模板可以做的工作:

#include <sstream> 
#include <string> 

template<class T> T CvtTo(const std::string& s) 
{ 
    stringstream ss; 
    ss << s; 
    T ret; 
    ss >> ret; 
    return ret; 
} 

現在完全接受你的需要的分支邏輯和呼叫CvtTo當你要存儲數據:

// SOME DATABASE FUNCTION N STUFF 

std::string value = ...; // VALUE TO BE CONVERTED & STORED 

enum FieldType {String, Int, Float}; 
FieldType field_type = ...; 

switch(field_type) 
{ 
case String : 
    store_a_string(CvtTo<std::string>(value)); // note this is not strictly necesarry for String 
    break; 

case Int : 
    store_an_int(CvtTo<int>(value)); 
    break; 

case Float : 
    store_a_float(CvtTo<float>(value)); 
    break; 
} 
// FURTHER MAGIC... 
相關問題