[英]Unexpected overload resolution in visual studio involving void*, string and const char[]
I got following unexpected overload resolution behavior with the visual studio compiler (tested in VS2010 and VS2012). 我使用visual studio编译器(在VS2010和VS2012中测试)获得了意外的重载解析行为。
Minimal example: 最小的例子:
#include <iostream>
#include <string>
void f(void *)
{
std::cout << "f(void*)\n";
}
void f(const std::string &)
{
std::cout << "f(const std::string &)\n";
}
int main()
{
f("Hello World!");
}
Output: 输出:
> f(void *)
Expected Ouptut: 预期的Ouptut:
> f(const std::string &)
Compiling with GCC(tested with 4.6.3) generates the expected output. 使用GCC进行编译(使用4.6.3测试)可生成预期输出。
If I comment out the "const std::string &" version of f(), visual studio happily compiles on /W4 without any warnings, while GCC emits following error (as expected): "invalid conversion from 'const void*' to 'void*' [-fpermissive]". 如果我注释掉f()的“const std :: string&”版本,visual studio很乐意在没有任何警告的情况下编译/ W4,而GCC会发出以下错误(如预期的那样):“从'const void *'无效转换为'void *'[-fpermissive]“。
Does anyone know why visual studio behaves in that way, choosing basically a const cast overload over a conversion to std::string for char[]? 有谁知道为什么visual studio以这种方式运行,基本上选择const转换重载转换为std :: string for char []?
Is there any way to prohibit this behavior, or at least get VS to generate a warning? 有没有办法禁止这种行为,或者至少让VS生成警告?
For VS 2013 Microsoft documents silently dropping const
for string literals as a Microsoft-specific behavior for C++: 对于VS 2013 Microsoft文档静默地删除字符串文字的const
作为C ++的Microsoft特定行为:
Microsoft Specific 微软特定
In Visual C++ you can use a string literal to initialize a pointer to non-const char or wchar_t. 在Visual C ++中,您可以使用字符串文字初始化指向非const char或wchar_t的指针。 This is allowed in C code, but is deprecated in C++98 and removed in C++11. 这在C代码中是允许的,但在C ++ 98中已弃用,在C ++ 11中已删除。
... ...
You can cause the compiler to emit an error when a string literal is converted to a non_const character when you set the
/Zc:strictStrings
(Disable string literal type conversion) compiler option. 当您在设置/Zc:strictStrings
(禁用字符串文字类型转换)编译器选项时将字符串文字转换为non_const字符时,可能会导致编译器发出错误。
For versions earlier than VS 2013 (for example VS 2012's documentation ), Microsoft documents string literals in C++ as using the C convention of being non-const array of char
. 对于VS 2013之前的版本(例如VS 2012的文档 ),Microsoft将C ++中的字符串文字记录为使用非常量char
数组的C约定。
I don't see why it is unexpected. 我不明白为什么会出乎意料。 The conversion of char const[]
to a std::string
involves a user defined conversion; char const[]
到std::string
转换涉及用户定义的转换; the conversion to void*
doesn't. 转换为void*
不会。 And a conversion involving a user defined conversion is always "less good" than one which doesn't involve a user defined conversion. 并且涉及用户定义的转换的转换总是“不太好”而不涉及用户定义的转换。
The real issue here is that C++ doesn't have a built-in string type, and the string literals don't have type std::string
. 这里真正的问题是C ++没有内置字符串类型,字符串文字没有类型std::string
。 The normal solution is to provide an overload for char const*
as well: 通常的解决方案是为char const*
提供重载:
void f( void* );
void f( std::string const& );
inline void f( char const* p ) { f( std::string( p ) ); }
This additional overload will pick up string literals. 这个额外的重载将获取字符串文字。
(As a general rule: anytime you're overloading: if one of the overloads is for std::string
, provide one for char const*
as well, if any are for arithmetic types, provide one for int
, to catch integral literals, and if any are for a floating point type, provide one for double
, to catch floating point literals.) (作为一般规则:任何时候你重载:如果其中一个重载用于std::string
,也为char const*
提供一个,如果有任何算术类型,为int
提供一个,以捕获整数文字,如果有任何浮点类型,请提供一个double
精度数来捕获浮点文字。)
The apparent issue is, as noted by others, that MSVC allows implicit conversion from string literals to non- const
char*
, and thence to void*
. 正如其他人所指出的那样,明显的问题是MSVC允许从字符串文字隐式转换为非const
char*
,从而转换为void*
。
I say apparent because your void*
overload should be a void const*
overload, as it does not change the pointed to data. 我说明显是因为你的void*
重载应该是一个void const*
重载,因为它不会改变指向数据。 Doing so will make things 'worse', as calling it with a string literal will now unambiguously select the void const*
overload. 这样做会使事情“变得更糟”,因为用字符串文字调用它现在将明确地选择void const*
overload。 However this illustrates what is going wrong: ""
is a char const(&)[1]
(an array of const char
), not a std::string
, and char const(&)[1]
is closer related to pointers than to std::string
. 然而,这说明了什么是错误: ""
是一个char const(&)[1]
(一个const char
数组),而不是一个std::string
,而char const(&)[1]
与指针的关系比到std::string
。 Relying on the overload picking std::string
over a pointer is fragile, even on gcc, as making your code const
correct breaks it! 依赖于指针的重载选择std::string
是脆弱的,即使在gcc上,因为使你的代码const
正确打破它!
To fix this we can write a greedy overload for std::string
. 为了解决这个问题,我们可以为std::string
编写一个贪心重载。
template<typename S, typename=typename std::enable_if<std::is_convertible<S,std::string>::value>::type>
void f(S&&s){
f(std::string{std::forward<S>(s)});
}
with the above two overloads left intact (except const
added). 上面两个重载保持完整(除了const
添加)。
Or (better) via tag dispatching: 或者(更好)通过标签调度:
void f(void const* v, std::false_type){
std::cout << "f(void*)\n";
}
void f(std::string const& s, std::true_type){
std::cout << "f(const std::string &)\n";
}
template<typename T>
void f(T&&t){
return f(std::forward<T>(t), std::is_convertible<T,std::string>() );
}
both of which are ways to do manual function overload dispatching, biased towards std::string
. 这两种方法都是手动函数重载调度,偏向于std::string
。
Note that std::string
literals are now possible in C++, but I would advise against requiring them on the basis of fragility. 请注意,现在可以在C ++中使用std::string
文字,但我建议不要在脆弱的基础上要求它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.