2012-05-19 11 views
47

counter è un intstd :: to_string - più di un'istanza di funzione in overload corrisponde la lista degli argomenti

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

Quale sarebbe il modo migliore per fermare questo errore? Quando ero pigro ho appena realizzato l'int long long (o qualcosa del genere), ma sono sicuro che c'è un modo migliore per risolvere questo problema.

Messaggio di errore:

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

Sto usando Visual C++ 2010 Express.

+0

Potrebbe includere il messaggio di errore effettivo e quale compilatore e versione si sta utilizzando (non riproducibile con GCC 4.5). – Mat

+0

OK - vedi modifica. – pighead10

risposta

79

In VC++ 2010 ci sono tre sovraccarichi di std::to_string che prendono long long, unsigned long long, e long double rispettivamente - chiaramente int è nessuna di queste, e nessuno di conversione è migliore di un altro (demo), in modo che la conversione non può essere fatto in modo implicito/senza ambiguità.

In termini di reale supporto C++ 11, questo è un difetto da parte di VC++ implementazione della libreria standard 2010 - lo standard C++ 11 si chiama in realtà per nove sovraccarichi di 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); 

aveva tutti questi sovraccarichi stati presenti, ovviamente sarebbe non hanno questo problema; tuttavia, VC++ 2010 non era basato sull'effettivo standard C++ 11 (che non esisteva ancora al momento della sua versione), ma piuttosto su N3000 (da), che fa non sovraccarichi. Di conseguenza, è dura per colpa di VC++ troppo molto qui ...

In ogni caso, per solo una manciata di chiamate, non c'è niente di sbagliato con l'utilizzo di un cast per risolvere l'ambiguità da soli:

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

oppure, se c'è un utilizzo intenso del std::to_string nel vostro codice di base, scrivere un paio di involucri e utilizzare quelli invece - in questo modo, non è necessaria alcuna chiamata in loco casting:

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

Non riesco a verificare se VC++ 2010 ha esito positivo o negativo con l'utilizzo sopra di SFINAE; se fallisce, le seguenti - utilizzando tag invio invece di SFINAE - dovrebbe essere compilabile (se potenzialmente meno chiaro):

#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

Tutti i sovraccarichi sono presenti in Visual C++ 11 Beta. Non è in realtà un fallimento nell'implementazione della libreria standard: alcuni degli overload sono stati aggiunti a C++ 11 _after_ è stato rilasciato Visual C++ 2010. –

+0

@James: corretto, modificato per riflettere questo. – ildjarn

+1

Rapporto sui difetti 1261 avvenuto nel 2009; Penso che sia ragionevole incolpare Microsoft di un * piccolo * per spostarsi lentamente, almeno. – zwol

9

Hai inciampato C++ DR 1261, che recita in parte

Il codice " int i; to_string(i); "non riesce a compilare, poiché 'int' è ambiguo tra 'long long' e 'long long unsigned'. Sembra irragionevole aspettarsi che gli utenti inseriscano numeri fino a un tipo più grande solo per utilizzare to_string.

La risoluzione proposta è di aggiungere più sovraccarichi.GCC has implemented this already; Suppongo che MSVC non lo sia.

+4

La risoluzione è stata incorporata nell'ultimo standard C++ 11. La Beta di Visual C++ 11 include tutti gli overload. –

Problemi correlati