2012-05-19 27 views
47

counter là một intstd :: to_string - hơn thể hiện của chức năng quá tải phù hợp với danh sách đối số

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

Điều gì sẽ là cách tốt nhất để ngăn chặn lỗi này? Khi tôi đang lười biếng tôi chỉ cần thực hiện các int long long (hoặc một cái gì đó), nhưng tôi chắc chắn có một cách tốt hơn để giải quyết này.

Thông báo lỗi:

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

Tôi đang sử dụng Visual C++ 2010 Express.

+0

Bạn có thể bao gồm thông báo lỗi thực tế và trình biên dịch & phiên bản bạn đang sử dụng (không thể tái sản xuất với GCC 4.5) hay không. – Mat

+0

OK - xem chỉnh sửa. – pighead10

Trả lời

79

Trong VC++ 2010 có ba quá tải của std::to_string mà phải mất long long, unsigned long long, và long double, tương ứng - rõ ràng int là không ai trong số này, và không có ai chuyển đổi là tốt hơn so với khác (demo), do đó việc chuyển đổi không thể được thực hiện ngầm/unambiguously.

Xét về hỗ trợ thực C++ 11, đây là một thất bại trên một phần của VC++ thực hiện tiêu chuẩn thư viện năm 2010 - tiêu chuẩn C++ 11 bản thân thực sự đòi hỏi chín quá tải của 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); 

đã tất cả các quá tải có mặt, bạn rõ ràng là sẽ không có vấn đề này; tuy nhiên, VC++ 2010 không dựa trên tiêu chuẩn C++ 11 thực tế (mà chưa tồn tại tại thời điểm phát hành), nhưng thay vào đó là N3000 (từ), thì không phải gọi cho những bổ sung này quá tải. Do đó, nó khắc nghiệt để đổ lỗi VC++ quá nhiều ở đây ...

Trong mọi trường hợp, chỉ một số ít các cuộc gọi, không có gì sai với việc sử dụng một dàn diễn viên để giải quyết sự mơ hồ tự hỏi:

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

hoặc, nếu có sử dụng nặng của std::to_string trong codebase của bạn, hãy viết một vài giấy gói và sử dụng những thay - Bằng cách này, không đúc gọi tại chỗ là cần thiết:

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

Tôi không thể kiểm tra xem VC++ 2010 thành công hay thất bại với việc sử dụng SFINAE ở trên; nếu nó không thành công, sau đây - sử dụng thẻ công văn thay vì SFINAE - nên compilable (nếu có khả năng chưa rõ ràng):

#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

Tất cả các tình trạng quá tải đều có trong Visual C++ 11 Beta. Nó không thực sự là một thất bại của việc thực hiện thư viện chuẩn: một số các tình trạng quá tải đã được thêm vào C++ 11 _after_ Visual C++ 2010 đã được phát hành. –

+0

@James: Đúng, chỉnh sửa để phản ánh điều đó. – ildjarn

+1

Báo cáo lỗi 1261 đã xảy ra trong năm 2009; Tôi nghĩ rằng nó là hợp lý để đổ lỗi cho Microsoft một chút * cho di chuyển chậm, ít nhất. – zwol

9

Bạn đã vấp C++ DR 1261, mà đọc trong phần

Mã " int i; to_string(i); "không biên dịch được, vì 'int' không rõ ràng giữa 'long long' và 'long long unsigned'. Có vẻ như không hợp lý để mong đợi người dùng truyền số lên một loại lớn hơn chỉ để sử dụng to_string.

Độ phân giải được đề xuất là thêm quá tải.GCC has implemented this already; Tôi đoán là MSVC không có.

+4

Độ phân giải được đưa vào tiêu chuẩn C++ 11 cuối cùng. Visual C++ 11 Beta bao gồm tất cả các tình trạng quá tải. –

Các vấn đề liên quan