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

Posted

技术标签:

【中文标题】std::to_string - 多个重载函数的实例与参数列表匹配【英文标题】:std::to_string - more than instance of overloaded function matches the argument list 【发布时间】:2012-05-26 17:46:13 【问题描述】:

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。

【问题讨论】:

您能否提供实际的错误消息,以及您使用的编译器和版本(GCC 4.5 无法重现)。 【参考方案1】:

在 VC++ 2010 中,std::to_string 的三个重载分别采用 long longunsigned long longlong double — 显然 int 不是这些,而且没有一种转换比另一种更好(@ 987654321@),因此不能隐式/明确地进行转换。

就真正的 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);

如果所有这些重载都存在,您显然不会遇到这个问题;然而,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>());

【讨论】:

所有重载都存在于 Visual C++ 11 Beta 中。这并不是标准库实现的真正失败:一些重载被添加到 C++11 Visual C++ 2010 发布之后。 缺陷报告 1261 发生在 2009 年;我认为至少有点责备微软行动缓慢是合理的。 选择一个标准的草稿版本来实施,然后不关注错误修复,这不是我所说的最佳实践。 The IE team does this too 真气。 @Zack : 好吧,没有人指责 MS 遵循最佳实践... ;-] FYI g++ CentOS-6 上的 4.4.7 版也有同样的问题(并且也来自与上述 MSVC 编译器相似的时间范围)。【参考方案2】:

你被C++ DR 1261绊倒了,它的部分内容

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

建议的解决方案是添加更多重载。 GCC has implemented this already;我猜 MSVC 没有。

【讨论】:

该决议被纳入最终的 C++11 标准。 Visual C++ 11 Beta 包含所有重载。

以上是关于std::to_string - 多个重载函数的实例与参数列表匹配的主要内容,如果未能解决你的问题,请参考以下文章

std::to_string(double) 的精度

如何在函数重载的情况下选择性地替换 Visual Studio 中的函数?

Python 没有函数重载?如何用装饰器实现函数重载?

有没有一种简单的方法可以将前导零添加到通过 std::to_string(int) 创建的字符串中?

编译器不知道std :: to_string? (C ++,即使在补丁之后)[重复]

为什么 Python 没有函数重载?如何用装饰器实现函数重载?