std :: to_string - 超过重载函数的实例与参数列表匹配

pig*_*d10 53 c++ visual-studio-2010 visual-c++ c++11

counter 是一个 int

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

什么是阻止此错误的最佳方法?当我懒惰时,我只是制作了int long long(或其他东西),但我确信有更好的解决方法.

错误信息:

sentrymanager.cpp(8): error C2668: 'std::to_string' : ambiguous call to overloaded function
Run Code Online (Sandbox Code Playgroud)

我正在使用Visual C++ 2010 Express.

ild*_*arn 87

在VC++ 2010有三个重载std::to_string称取long long,unsigned long longlong double,分别为-显然int是没有这些,没有一个转换比另一个(更好的演示),所以转换不能隐完成/明确.

就真正的C++ 11支持而言,这是VC++ 2010标准库实现的一个失败 - C++ 11标准本身实际上要求九次重载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);
Run Code Online (Sandbox Code Playgroud)

如果所有这些重载都存在,你显然不会有这个问题; 然而,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));
}
Run Code Online (Sandbox Code Playgroud)

或者,如果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);
}
Run Code Online (Sandbox Code Playgroud)

我无法检查VC++ 2010是否成功使用SFINAE; 如果失败,以下 - 使用标签调度而不是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>());
}
Run Code Online (Sandbox Code Playgroud)

  • 所有重载都存在于Visual C++ 11 Beta中.这并不是标准库实现的失败:一些重载被添加到C++ 11 _ after_ Visual C++ 2010发布. (3认同)
  • 选择一个标准的草稿版本来实施,然后不关注错误修复,这并不是我所说的最佳实践。[IE 团队也这样做](https://groups.google.com/d/topic/mozilla.dev.platform/TcY72dL4AB4/discussion),这令人愤怒。 (2认同)

zwo*_*wol 11

你已经绊倒了C++ DR 1261,它部分读取

代码" int i; to_string(i);"无法编译,因为int' long long'和' long long unsigned' 之间的' ' 不明确.期望用户将数字转换为更大类型只是为了使用似乎是不合理的to_string.

拟议的决议是增加更多的重载. GCC已经实现了这一点 ; 我猜MSVC没有.

  • 该决议已纳入最终的C++ 11标准.Visual C++ 11 Beta包含所有重载. (4认同)