2011-09-14 11 views
3

型をマップする必要がある2つのシステムがあります。ソースデータフィールド(数値、文字または文字列)はすべて文字列オブジェクトとして格納されます。宛先システムは、各データフィールドの基礎となるタイプの異なるデータタイプを必要とし、このマッピングを動的に行う必要があります。異なるテンプレート引数に基づいて異なるデータ型に変換する

基本的に、各データフィールドに対して、実際のフィールド文字列 's'と基になるデータの型 'type'があり、 'type'に基づいて 'dest'型に変換しようとしています。 。私はテンプレートとテンプレート定数を使ってこれをやり遂げることができます。

は、私が持っている現在の試みは以下の通りであるが、これは矛盾する戻り値の型が原因でコンパイルされません。だから私は誰にもお勧めします

string mapped = returnDifferentTypes<string, 1>() 

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

のようなものを呼び出してきた

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

これを行うスマータークリーナーの方法?理想的には、マップする型を表す文字列だけで適切な戻り値の型を返そうとしています。前もって感謝します。

答えて

2

IDを静的に識別できるのであれば、テンプレートの正規化は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); 

それとも - すべての例で必要とされるより少ない正統派の、それでももちろん

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

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

working-、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をシンプルCvtTo関数テンプレートは、仕事をすることができます。これは適切な解決策です。 – Nawaz

+0

私は通常、関数テンプレートを特化することには注意していますが、別のデザインが良いかもしれません。 –

0

、あなたはboost::variantまたは多分boost::anyを探しています。

しかし、なぜこの動作が必要なのか、そして同じ機能から複数の異なるタイプを返す必要性を排除する別の方法があるかどうかを考えてみてください。

0

数値やその他の「iostreamシリアライズ可能」タイプを文字列との間で変換する場合は、boost::lexical_castを使用できます。

1

stringの代わりに何らかの種類のVariantクラスを使用してすべてを格納しない限り、コード内のある時点でタイプ間で選択する分岐のフォームが必要になります。しかし、変換関数自体はそのための場所ではありません。変換関数は1つの型だけを返すことができます。その中で分岐しようとすると、3つの型を返す必要があります。もう一度Variantやその他の醜いハック(例:void*)を使用しない限り、これは動作しません。

関数テンプレートの特殊化を使用すると、種類を区別する分岐どこかを持つ受け入れると仮定すると、ここで必要とされていません。

#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... 
関連する問題