Std:: to_string - больше чем экземпляр перегруженной функции соответствует списку аргументов

counter является int

void SentryManager::add(std::string name,std::shared_ptr<Sentry>){
    name = name + std::to_string(counter);
}

Каким будет лучший способ остановить эту ошибку? Когда я ленился, я просто сделал int long long (или что-то еще), но я уверен, что есть лучший способ решить это.

Сообщение об ошибке:

sentrymanager.cpp(8): error C2668: 'std::to_string' : ambiguous call to overloaded function

Я использую Visual С++ 2010 Express.

Ответ 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>());
}

Ответ 2

Вы сработали С++ DR 1261, который читается частично

Код "int i; to_string(i);" не скомпилируется, так как "int" является неоднозначным между "long long" и "long long unsigned". Кажется неоправданным ожидать, что пользователи будут набирать номера до более крупного типа, просто используя to_string.

Предлагаемая резолюция заключается в добавлении дополнительных перегрузок. GCC уже реализовал это; Я думаю, что MSVC не имеет.