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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10664699/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:18:55  来源:igfitidea点击:

std::to_string - more than instance of overloaded function matches the argument list

c++visual-studio-2010visual-c++c++11

提问by pighead10

counteris an int

counter是一个 int

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

What would be the best way to stop this error? When I was being lazy I just made the int long long(or something), but I'm sure there is a better way of solving this.

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

Error message:

错误信息:

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

I am using Visual C++ 2010 Express.

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

回答by ildjarn

In VC++ 2010 there are three overloads of std::to_stringthat take long long, unsigned long long, and long double, respectively – clearly intis none of these, and no one conversion is better than another (demo), so the conversion cannot be done implicitly/unambiguously.

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

In terms of real C++11 support, this is a failing on the part of VC++ 2010's standard library implementation – the C++11 standard itself actually calls for nineoverloads of std::to_string([string.conversions]/7):

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

Had all of these overloads been present, you obviously wouldn't have this problem; however, VC++ 2010 wasn't based on the actual C++11 standard (which did not yet exist at the time of its release), but rather on N3000(from 2009), which does notcall for these additional overloads. Consequently, it's harsh to blame VC++ toomuch here...

如果所有这些重载都存在,你显然不会有这个问题;然而,VC ++ 2010并非基于实际C ++ 11的标准(这还不存在在其发布的时间),而是基于N3000(自2009年),这并没有要求这些额外的过载。因此,在这里过多地责怪 VC++ 是苛刻的......

In any case, for only a handful of calls, there's nothing wrong with using a cast to resolve the ambiguity yourself:

在任何情况下,对于少数调用,使用强制转换自己解决歧义并没有错:

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

Or, if there's heavy usage of std::to_stringin your codebase, write a few wrappers and use those instead – this way, no call-site casting is needed:

或者,如果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);
}


I can't check whether VC++ 2010 succeeds or fails with the above usage of SFINAE; if it fails, the following – using tag dispatch instead of SFINAE – should be compilable (if potentially less clear):

我无法通过上述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>());
}

回答by zwol

You have tripped over C++ DR 1261, which reads in part

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

The code "int i; to_string(i);" fails to compile, as 'int' is ambiguous between 'long long' and 'long long unsigned'. It seems unreasonable to expect users to cast numbers up to a larger type just to use to_string.

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

The proposed resolution is to add more overloads. GCC has implemented this already; I guess MSVC hasn't.

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