Ответ 1
В VС++ 2010 есть три перегрузки std::to_string
, которые принимают long long
, unsigned long long
и long double
соответственно - ясно, что int
не является ни одним из них, и ни одно преобразование не лучше другого (demo), поэтому преобразование невозможно сделать неявно/недвусмысленно.
В терминах реальной поддержки С++ 11 это является провалом со стороны реализации стандартной библиотеки VС++ 2010 - сам стандарт С++ 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);
Если бы все эти перегрузки присутствовали, у вас, очевидно, не было бы этой проблемы; однако VС++ 2010 не был основан на фактическом стандарте С++ 11 (который еще не существовал на момент его выпуска), а скорее на N3000 (с 2009 г.), что не требует дополнительных перегрузок. Следовательно, это жестко обвинять VС++ слишком много здесь...
В любом случае, только для нескольких вызовов, нет ничего плохого в использовании приведения, чтобы решить эту двусмысленность:
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);
}
Я не могу проверить, успешно ли или не удалось выполнить VС++ 2010 с использованием вышеприведенного использования SFINAE; если это не удается, следующее - использование отправки тегов вместо SFINAE - должно быть скомпилировано (если это будет менее понятно):
#include <type_traits>
#include <string>
namespace detail {
template<typename T>
inline std::string
to_string(T const val, std::false_type /*is_float*/, std::false_type /*is_unsigned*/) {
return std::to_string(static_cast<long long>(val));
}
template<typename T>
inline std::string
to_string(T const val, std::false_type /*is_float*/, std::true_type /*is_unsigned*/) {
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 /*is_float*/, _) {
return std::to_string(static_cast<long double>(val));
}
} // namespace detail
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>());
}