Преобразование в разные типы данных на основе разных аргументов шаблона - PullRequest
3 голосов
/ 14 сентября 2011

У меня есть две системы, которые мне нужны для сопоставления типов: поля исходных данных, которые могут быть числовыми, символами или строками, хранятся как строковые объекты;системе назначения требуется другой тип данных для базового типа каждого поля данных, и мне нужно динамически выполнить это отображение.

Таким образом, в основном для каждого поля данных у меня есть фактическая строка поля 's' итип базовых данных, «тип», и я пытаюсь преобразовать в тип «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 ]

5 голосов
/ 14 сентября 2011

Для вашего случая 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>();
3 голосов
/ 14 сентября 2011

Если вы можете различить идентификатор статически, 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);

Или - менее православный, но все еще работающий -

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 должна быть откорректирована, как требуется во всех примерах.

1 голос
/ 14 сентября 2011

Если вы не используете какой-то класс 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...
0 голосов
/ 14 сентября 2011

Если вы хотите преобразовать числовые значения или другие типы «iostream serializable» в строку и из строки, вы можете использовать boost::lexical_cast.

0 голосов
/ 14 сентября 2011

Если вы действительно хотите функцию, которая может возвращать несколько типов, вы ищете boost::variant или, возможно, boost::any.

Однако, пожалуйста, по крайней мере, подумайте, почему вам нужно такое поведение, и если есть альтернативный подход, который может устранить необходимость возвращать несколько разных типов из одной и той же функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...