54

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 C++ 2010 Express。

4

2 回答 2

87

在 VC++ 2010 中,分别有三个重载std::to_stringtake long longunsigned long longlong double—— 显然int这些都不是,而且没有一个转换比另一个更好(demo),所以转换不能隐式/明确地完成。

就真正的 C++11 支持而言,这是 VC++ 2010 标准库实现部分的失败——C++11 标准本身实际上需要([string.conversions]/7)的九个重载:std::to_string

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

如果所有这些重载都存在,您显然不会遇到这个问题;但是,VC++ 2010 并不是基于实际的 C++11 标准(在其发布时还不存在),而是基于N3000(从2009 年开始),它不需要这些额外的重载。因此,在这里过多地责怪VC++是很苛刻的......

无论如何,对于少数几个调用,使用强制转换自己解决歧义并没有错:

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

我无法通过上述 SFINAE 用法检查 VC++ 2010 是成功还是失败;如果失败,以下内容——使用标签调度而不是 SFINAE——应该是可编译的(如果可能不太清楚):

#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>());
}
于 2012-05-19T15:51:53.617 回答
11

您已经绊倒了C++ DR 1261,其中部分内容为

代码 " int i; to_string(i);" 无法编译,因为 ' ' 在 ' ' 和 ' 'int之间有歧义。期望用户为了使用而将数字转换为更大的类型似乎是不合理的。long longlong long unsignedto_string

建议的解决方案是添加更多的重载。 GCC 已经实现了这一点;我猜MSVC没有。

于 2012-05-19T15:57:18.680 回答