根据不同的模板参数转换为不同的数据类型

时间:2011-09-14 14:43:15

标签: c++ templates

我需要两个系统来映射类型 - 源数据字段,可以是数字,字符或字符串,都存储为字符串对象;目标系统需要为每个数据字段的基础类型使用不同的数据类型,我需要动态地执行此映射。

所以基本上,对于每个数据字段,我都有实际的字段字符串'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>()

任何人都可以推荐更智能的清洁方式来做到这一点吗?理想情况下,我试图返回适当的返回类型,只有一个表示要映射到的类型的字符串。提前谢谢。

5 个答案:

答案 0 :(得分: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 :(得分:3)

如果您可以静态识别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();

当然,必须根据所有示例的要求调整const正确性。

答案 2 :(得分:1)

除非你使用某种Variant类而不是string来存储所有内容,否则在代码中的某些时候你需要有一种在类型之间选择的分支形式。但是,转换函数本身并不适合它。转换函数只能返回一种类型。如果您尝试在其中分支,则需要返回三种类型。除非你使用Variant或其他一些丑陋的黑客(例如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...

答案 3 :(得分:0)

如果您真的想要一个可以返回多种类型的函数,那么您正在寻找boost::variantboost::any

但是,请至少花点时间考虑一下为什么要这种行为,以及是否存在可能无需从同一函数返回多个不同类型的替代方法。

答案 4 :(得分:0)

如果要将数值或其他“iostream可序列化”类型转换为字符串,可以使用boost::lexical_cast