我曾经在下面看到这个很好的一小段代码,在这里:SO:
template<typename to_t, typename from_t>
to_t lex_cast(const from_t &arg) {
to_t ret;
std::stringstream os;
os << arg;
os >> ret;
return ret;
}
这模仿boost :: lexical_cast。用法:
string tmp = ::lex_cast<string>(3.14);
但是,由于格式化流的默认跳过,以下内容将无法按预期工作:
string tmp = ::lex_cast<string>("foo bar"); // will only return foo, but I want entire string
(我期待与\ n的类似问题)。 我试图设置noskipws和模板专业化但无济于事。请指教。
答案 0 :(得分:3)
实际上,要涵盖从字符串转换为字符串的所有可能情况,您需要一个相当复杂的机制。我在下面粘贴了一个可能的实现,但这肯定会让你不想使用boost::lexical_cast
。
//Beware, brain-compiled code ahead!
namespace detail {
template< typename T, typename S >
struct my_lexical_caster {
static T my_lexical_cast(const S& s) {
std::stringstream ss;
if( !(ss << s) ) throw std::bad_cast("cannot stream from source");
T t;
if( !(ss >> t) ) throw std::bad_cast("cannot stream to target");
return t;
}
};
template< typename S >
struct my_lexical_caster<std::string,S> {
static std::string my_lexical_cast(const S& s) {
std::ostringstream oss;
if( !(oss << s) ) throw std::bad_cast("cannot stream from source");
return oss.str();
}
};
template< typename T >
struct my_lexical_caster<T,std::string> {
static T my_lexical_cast(const std::string& s) {
std::stringstream ss(s);
T t;
if( !(ss >> t) ) throw std::bad_cast("cannot stream to target");
return t;
}
};
template< typename T >
struct my_lexical_caster<T,T> {
static const T& my_lexical_cast(const T& s) {return s;}
};
template<>
struct my_lexical_caster<std::string,std::string> {
static const std::string& my_lexical_cast(const std::string& s) {return s;}
};
}
template< typename T, typename S >
inline T my_lexical_cast(const S& s)
{
return detail::my_lexical_caster<T,S>::my_lexical_cast(s);
}
首先,看看我们在这里有两个模板参数,其中一个参数决定my_lexical_cast<>()
的 返回类型 。现在我们必须为某些特殊类型提供特殊实现。虽然我们可以根据不同的函数参数 重载 函数,但我们不能根据返回值重载它们。因此,我们需要 专门化 模板,而不是重载功能模板。
然而,这也带来了一个问题:功能模板没有 部分特化 ,只有完全专业化。通常给出的原因是 而不是功能模板部分特化我们有重载功能模板 。虽然这可能是,但是当涉及到返回类型时,它对我们没有帮助
绕过缺失函数模板部分特化的常用方法是使用 _class模板部分特化,因为它是可用的。这是通过创建类模板并在其公共静态成员函数中实现算法来完成的。然后,类模板可以是部分专用的,并且每个特化都可以带有自己的静态成员函数实现
因此,这解释了为什么在detail
命名空间中存在类模板(实际上它们是结构体,但这只是为了节省我们明确地将其唯一成员公开的麻烦)。
首先,肯定需要一个 通用实现 ,它可以从任何可流式转换为任何其他类型。
然后,正如您所观察到的,我们需要一个专门化来涵盖我们想要 转换为字符串 的情况,因为在这种情况下默认实现是错误的。
与 两个模板参数属于同一类型 的情况相匹配的是纯优化:如果要将int
转换为int
,我们可以分发原始价值。你可能会问自己为什么有人想要这样做,但在模板代码中,人们不知道代码可能被调用的类型,这样的事情总是发生。
从字符串转换为任何其他类型 的专业化也是一种优化。它避免了将字符串流式传输到流中,而是直接初始化输出字符串流。这假设后者实际上比前者更快。虽然我没有测量过这个,但我认为我们可以放心地认为它永远不会慢。
留下最后一个,将 字符串“转换”为字符串 。为什么我们需要这个,是不是已经涵盖了“转换”和T
到T
的情况?嗯,是的,它是,我们也可以使用这个,因为从语义上讲,它做的是正确的。但是编译器并不关心 语义 ,它唯一关心的是 语法 。当您想要将std::string
“转换”为std::string
时,编译器会找到三个与部分匹配的特化:<T,std::string>
,<std::string,T
,和<T,T>
。由于它不知道在这种情况下该做什么并引发错误,我们需要通过提供 一致更好的匹配来帮助它,而不是任何这些 三。