2012-05-19 26 views
47

counter es un intstd :: to_string - más de instancia de función sobrecargada coincide con la lista de argumentos

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

¿Cuál sería la mejor manera de detener este error? Cuando estaba siendo flojo acabo de hacer el int long long (o algo así), pero estoy seguro de que hay una mejor manera de resolver esto.

mensaje de error:

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

Estoy utilizando Visual C++ 2010 Express.

+0

Podría incluir el mensaje de error real y el compilador y la versión que está utilizando (no reproducible con GCC 4.5). – Mat

+0

Bien - ver edición. – pighead10

Respuesta

79

En VC++ 2010 hay tres sobrecargas de std::to_string que tienen long long, unsigned long long, y long double, respectivamente - con claridad int es ninguno de estos, y nadie conversión es mejor que otro (demo), por lo que la conversión no se puede hacer de forma implícita/sin ambigüedades

En términos de apoyo real de C++ 11, se trata de un fallo por parte de VC++ implementación de la biblioteca estándar de 2010 - el estándar de C++ 11 en sí en realidad llama a nueve sobrecargas de 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); 

tenía todas estas sobrecargas estado presentes, es obvio que no tendrías este problema; sin embargo, VC++ 2010 no se basó en el estándar C++ 11 real (que aún no existía en el momento de su lanzamiento), sino en N3000 (desde), que no hace no llamada para estos adicionales sobrecargas En consecuencia, es dura la culpa VC++ demasiado mucho aquí ...

En cualquier caso, sólo por un puñado de llamadas, no hay nada malo en usar un yeso para resolver la ambigüedad mismo:

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

o bien, si hay un uso intensivo de std::to_string en su base de código, escribir un par de envoltorios y utilizar aquellos en vez - de esta manera, no se necesita de fundición llamada in situ:

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

No puedo verificar si VC++ 2010 tiene éxito o falla con el uso anterior de SFINAE; si fracasa, el siguiente - el uso de la expedición de etiquetas en lugar de SFINAE - debe ser compilables (si es potencialmente menos clara):

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

Todas las sobrecargas están presentes en Visual C++ 11 Beta. En realidad, no se trata de una falla de la implementación de la Biblioteca estándar: algunas de las sobrecargas se agregaron a C++ 11 después de que se lanzó Visual C++ 2010. –

+0

@James: Correcto, editado para reflejar eso. – ildjarn

+1

Informe de defectos 1261 sucedió en 2009; Creo que es razonable culpar a Microsoft un * pequeño * por moverse lentamente, al menos. – zwol

9

Usted ha tropezado con C++ DR 1261, que dice en parte

El código " int i; to_string(i); "no se puede compilar, ya que 'int' es ambiguo entre 'long long' y 'long long unsigned'. Parece irrazonable esperar que los usuarios creen números hasta un tipo más grande solo para usar to_string.

La resolución propuesta es agregar más sobrecargas.GCC has implemented this already; Supongo que MSVC no.

+4

La resolución se incorporó en el estándar C++ 11 final. La versión Beta de Visual C++ 11 incluye todas las sobrecargas. –

Cuestiones relacionadas