54

counter is an int

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

What would be the best way to stop this error? When I was being lazy I just made the int long long (or something), but I'm sure there is a better way of solving this.

Error message:

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

I am using Visual C++ 2010 Express.

1
  • Could you include the actual error message, and what compiler & version you're using (not reproducible with GCC 4.5). Commented May 19, 2012 at 11:19

2 Answers 2

88

In VC++ 2010 there are three overloads of std::to_string that take long long, unsigned long long, and long double, respectively – clearly int is none of these, and no one conversion is better than another (demo), so the conversion cannot be done implicitly/unambiguously.

In terms of real C++11 support, this is a failing on the part of VC++ 2010's standard library implementation – the C++11 standard itself actually calls for nine overloads of 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); 

Had all of these overloads been present, you obviously wouldn't have this problem; however, VC++ 2010 wasn't based on the actual C++11 standard (which did not yet exist at the time of its release), but rather on N3000 (from 2009), which does not call for these additional overloads. Consequently, it's harsh to blame VC++ too much here...

In any case, for only a handful of calls, there's nothing wrong with using a cast to resolve the ambiguity yourself:

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

Or, if there's heavy usage of std::to_string in your codebase, write a few wrappers and use those instead – this way, no call-site casting is needed:

#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); } 

I can't check whether VC++ 2010 succeeds or fails with the above usage of SFINAE; if it fails, the following – using tag dispatch instead of SFINAE – should be compilable (if potentially less clear):

#include <type_traits> #include <string> namespace detail { template<typename T> // is_float is_unsigned 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> // is_float is_unsigned 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 _> // is_float 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>()); } 
Sign up to request clarification or add additional context in comments.

7 Comments

All of the overloads are present in the Visual C++ 11 Beta. It's not really a failing of the Standard Library implementation: some of the overloads were added to C++11 after Visual C++ 2010 was released.
Defect Report 1261 happened in 2009; I think it's reasonable to blame Microsoft a little for moving slowly, at least.
Picking a draft version of a standard to implement and not paying attention to bugfixes after that point is not what I would call best practice. The IE team does this too and it's infuriating.
@Zack : Well, no one ever accused MS of following best practices... ;-]
FYI g++ version 4.4.7 on CentOS-6 also has the same issue (and is also from a similar timeframe as the above mentioned MSVC compiler).
|
11

You have tripped over C++ DR 1261, which reads in part

The code "int i; to_string(i);" fails to compile, as 'int' is ambiguous between 'long long' and 'long long unsigned'. It seems unreasonable to expect users to cast numbers up to a larger type just to use to_string.

The proposed resolution is to add more overloads. GCC has implemented this already; I guess MSVC hasn't.

1 Comment

The resolution was incorporated into the final C++11 Standard. The Visual C++ 11 Beta includes all of the overloads.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.