在VC++ 2010中,有三个重载的
std::to_string
函数,分别接受
long long
、
unsigned long long
和
long double
类型的参数——显然
int
不属于这些类型,也没有一种转换比另一种更好(
demo),因此不能隐式/明确地进行转换。
就C++11的实际支持而言,这是VC++ 2010标准库实现的失败——C++11标准本身实际上要求有九个
std::to_string
的重载([string.conversions]/7)。
string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);
如果所有这些重载都存在,显然您就不会有这个问题。然而,VC++ 2010并非基于实际的C++11标准(因为在发布时它还不存在),而是基于2009年的
N3000,该标准不要求这些额外的重载。因此,在这里过分责备VC++是不公平的......
无论如何,对于只有少数调用,使用强制转换来解决歧义是没有问题的:
void SentryManager::add(std::string& name, std::shared_ptr<Sentry>) {
name += std::to_string(static_cast<long long>(counter));
}
或者,如果你的代码库中有大量使用 std::to_string
,可以编写一些包装器并使用它们替代 - 这样,就不需要在调用站点进行强制类型转换:
#include <type_traits>
#include <string>
template<typename T>
inline
typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, std::string>::type
to_string(T const val) {
return std::to_string(static_cast<long long>(val));
}
template<typename T>
inline
typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, std::string>::type
to_string(T const val) {
return std::to_string(static_cast<unsigned long long>(val));
}
template<typename T>
inline typename std::enable_if<std::is_floating_point<T>::value, std::string>::type
to_string(T const val) {
return std::to_string(static_cast<long double>(val));
}
void SentryManager::add(std::string& name, std::shared_ptr<Sentry>) {
name += to_string(counter);
}
我无法检查VC++ 2010是否成功使用上述SFINAE;如果它失败了,以下使用标签分派而不是SFINAE的方法应该是可以编译的(如果可能会更不清晰):
#include <type_traits>
#include <string>
namespace detail {
template<typename T>
inline std::string to_string(T const val, std::false_type, std::false_type) {
return std::to_string(static_cast<long long>(val));
}
template<typename T>
inline std::string to_string(T const val, std::false_type, std::true_type) {
return std::to_string(static_cast<unsigned long long>(val));
}
template<typename T, typename _>
inline std::string to_string(T const val, std::true_type, _) {
return std::to_string(static_cast<long double>(val));
}
}
template<typename T>
inline std::string to_string(T const val) {
return detail::to_string(val, std::is_floating_point<T>(), std::is_unsigned<T>());
}