我有这个模板函数,它从std::map
中获取一个元素作为字符串,并将其通过T
转换为通用std::stringstream operator>>
并返回。
但是提取运算符仅提取流中的第一个单词。
我已经尝试过.str()
,但是对于模板功能却没有。我也尝试过ss >> std::noskipws >> result;
,但它似乎未返回有效数据。
template<typename T>
T CConfig::get(const char *setting)
{
std::stringstream ss;
ss << this->m_settings[setting];
// this->m_settings[setting] = "this is a test"
T result;
ss >> result;
// result = "this"
return result;
}
我的期望是,如果m_settings [setting]为"this is a test"
,则在我的get
函数中将返回相同的字符串。同时,我不想通过硬编码ss.str()
并对字符串使用其他函数来破坏模板。
答案 0 :(得分:3)
您必须准确确定想要字符串的行为。如果要提取整行,可以使用std::getline()
。或者在这种情况下,可能只是return this->m_settings[setting];
。
无论您最终做什么,解决方案都是将变体行为放入get<std::string>
的专门化中。
请小心,专用行为与主代码的行为不要偏离得太远,因为这可能会使您的用户(包括您自己!)感到困惑。
答案 1 :(得分:1)
有3种方法:
就像我在评论中说的那样,您可以专用于功能get<std::string>
并从那里调用std::getline()
。
template<typename T>
T CConfig::get(const char* settings) {
std::istringstream stream(m_settings[settings]);
T t; assert(stream >> t);
return t;
}
template<>
std::string CConfig::get<std::string>(const char* settings) {
std::istringstream stream(m_settings[settings]);
T t; assert((std::getline(stream, t)));
return t;
}
这种方法的缺点是会导致代码重复。
委托给使用主要和专门的重载的辅助函数。
template<typename T>
T CConfig::get(const char* settings) {
T t;
assert(
do_get(std::istringstream(m_settings[settings]) >> std::skipws, t);
);
return t;
}
template<typename T>
bool do_get(std::istringstream& stream, T& data) {
return stream >> data;
}
template<>
bool do_get(std::istringstream& stream, std::string& data) {
return std::getline(stream, data);
}
如果您有c++17,则只需使用if constexpr
:
template<class T>
T CConfig::get(const char* settings) {
T t;
std::istringstream stream(m_settings[settings]);
if constexpr(std::is_same_v<T, std::string>) {
assert((std::getline(stream, t)));
} else {
assert(stream >> t);
}
return t;
}