2010-10-07 2 views
2

Я унаследовал шаблон для преобразования строки в числовое значение и хочу применить его для преобразования в boolean. Я не очень разбираюсь в классах stringstream и locale. Кажется, я получаю какое-то странное поведение, и мне интересно, может ли кто-нибудь объяснить это мне?num_get фасет и преобразование строки в boolean - сбой с инициализированным булевым?

template<typename T> T convertFromString(const string& str) const { 

std::stringstream SStream(str); 
T num = 0; 
SStream >> num; 

return num; 
} 

Это работает отлично, пока я пытаюсь логическое преобразование

string str1("1"); 
int val1 = convertFromString<int>(str1); // ok 
string str2("true"); 
bool val2 = convertFromString<bool>(str2); // val2 is _false_ 

Я провел некоторое время, выслеживая проблему. Я подтвердил, что truename locale() возвращает «true».

Проблема, похоже, связана с инициализацией переменной num. Я могу сменить шаблон на это, и он работает:

template<typename T> T convertFromString(const string& str) const { 

std::stringstream SStream(str); 
T num; // <----------------------- Changed here 
SStream >> num; 

return num; 
} 
string str2("true"); 
bool val2 = convertFromString<bool>(str2); // val2 is _true_ 

Почему это работает? Я согласен с тем, что инициализация bool с «0» неверна, но почему это приведет к ошибке преобразования SStream>>num?

ответ

7

Инициализация bool с помощью 0 надежно устанавливает значение false, и это не влияет на извлечение потока.

Причиной вашей проблемы является то, что потоки по умолчанию распознают значения 0 и 1 при работе с булевыми. Чтобы они узнали имена true и false, вам необходимо прямо указать потоку с помощью манипулятора boolalpha.

Лучшим способ для решения ваших проблем является специализировать шаблон для Его:

template<> bool convertFromString<bool>(const string& str) const { 
    std::stringstream SStream(str); 
    bool val = false; 
    SStream >> val; 
    if(SStream.fail()) 
    { 
    SStream.clear(); 
    SStream >> boolalpha >> val; 
    }  
    return val; 
} 

Обратите внимание, что изменение сделало не сделать код работу. Это просто оказалось для единственного теста, который вы использовали. С вашим изменением функция не прочитала из потока и вернула неинициализированное значение. Поскольку любое ненулевое значение будет интерпретироваться как истинное, функция работает, но как только вы попытаетесь извлечь "false", вы увидите, что он сбой (функция по-прежнему возвращает true).

Редактировать: Адаптированный код для обработки как числовых, так и альфа-букв.

+0

Это имеет смысл. После публикации я извлек код из основного архива, чтобы проверить его сам, и он, похоже, сработал. Несогласованность, хотя, как вы говорите, является унифицированным логическим (в основном «истинным» в одном контексте, в основном «ложным» в другом). – youngthing

+0

Благодарим вас за предоставление решения (boolalpha). – youngthing

+0

Чтобы распознать строки true/false и 1/0, кажется, что полезно попробовать один, а затем попробовать другое, если это не удается: if ('(SStream >> num) .fail()) {SStream.Чисто(); SStream >> boolalpha >> Num; } – youngthing

1

Это связано с тем, что преобразование stringstream из 'true' не работает - ваш шаблон функции должен проверить SStream.fail(), прежде чем он вернется, так что вы можете легко обнаружить подобные сбои.

При запуске bool его значение равно false. Когда вы не инициализируете его (после удаления = 0), это случайный мусор (обычно отличный от нуля) и возвращает true.

template<typename T> T convertFromString(const string& str) { 

std::stringstream SStream(str); 
T num = 0; 
SStream >> num; 

if (SStream.fail()) 
{ 
    // conversion failure - handle error 
    bool error = true; 
} 

return num; 
}