从支撑的std::string构造std::string_view,clang和gcc不同意-Wconversion
Constructing a std::string_view from a braced std::string, clang and gcc disagree with -Wconversion
GCC 7.2和clang 5.0在使用-std=c++17 -Werror -Wconversion
:编译时似乎对以下代码存在分歧
#include <iostream>
#include <string>
#include <string_view>
int main(int argc, char* argv[]) {
std::string s = "Hello, World";
std::string_view vs{s};
std::cout << std::string{vs} << 'n';
return EXIT_SUCCESS;
}
使用clang++ -std=c++17 -Wall -Werror -Wconversion
编译,它编译正确(请参阅https://godbolt.org/g/JZn8cL)
然而,GCC 7.2发布了一个有点令人困惑的诊断(参见https://godbolt.org/g/kmYbJ3):
<source>: In function 'int main(int, char**)':
7 : <source>:7:26: error: choosing 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::__sv_type() const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::__sv_type = std::basic_string_view<char>]' over 'constexpr std::basic_string_view<_CharT, _Traits>::basic_string_view(const std::basic_string_view<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits<char>]' [-Werror=conversion]
std::string_view vs{s};
^
7 : <source>:7:26: error: for conversion from 'std::__cxx11::string {aka std::__cxx11::basic_string<char>}' to 'std::basic_string_view<char>' [-Werror=conversion]
7 : <source>:7:26: note: because conversion sequence for the argument is better
cc1plus: all warnings being treated as errors
Compiler exited with result code 1
在将vs{s}
更改为vs(s)
之后,两个编译器都可以很好地编译代码。
哪一个编译器就在这里?std::string
对std::string_view
的大括号初始化是否以某种方式违反了转换规则,而clang在可能/应该发出诊断时未能发出诊断?或者GCC是错误的,诊断是错误的?
这里有哪个编译器?
两者都有?编译器可以根据自己的选择发出警告,也可以不发出警告。只是当你写的时候:
std::string_view vs{s};
你可能会觉得这是在做聚合初始化,或者至少调用string_view
构造函数,但事实并非如此——如果你写:
std::string_view vs(s);
所以gcc会给你一个警告(因为你要求警告)。
代码很好。两个编译器都很好。只要使用()
s进行初始化,就没有理由在这里使用{}
(这两种方法的行为没有区别)。
您最初的问题("这是无效的C++吗?")现在已经得到了回答("否"),但从评论中可以清楚地看出,您现在感兴趣的是为什么gcc会警告此有效代码。这是一个更有趣的问题。
删除模板参数后,警告减少为:
warning: choosing 'std::string::operator std::string_view()' over 'constexpr std::string_view(const std::string_view&) ' [-Wconversion]
因此,它警告用户定义的转换运算符被选择而不是构造函数。。。但该构造函数实际上不能用于转换。以下是另一个出于相同原因发出警告的例子:
class A { // Like string_view
public:
A() {}
};
class B { // Like string
public:
operator A() {return A();}
};
int main() {
B b;
A a{b};
}
这给出:
<source>: In function 'int main()':
12 : <source>:12:10: warning: choosing 'B::operator A()' over 'constexpr A::A(A&&)' [-Wconversion]
A a{b};
^
12 : <source>:12:10: warning: for conversion from 'B' to 'A' [-Wconversion]
12 : <source>:12:10: note: because conversion sequence for the argument is better
12 : <source>:12:10: warning: choosing 'B::operator A()' over 'constexpr A::A(const A&)' [-Wconversion]
12 : <source>:12:10: warning: for conversion from 'B' to 'A' [-Wconversion]
12 : <source>:12:10: note: because conversion sequence for the argument is better
顺便说一句,添加例如A(int)
构造函数不会给警告添加任何内容,因此它主要关注A
的移动构造函数和复制构造函数。删除带有=delete
的复制和移动构造函数也不会更改警告。
这澄清了引起警告的原因,但没有说明警告的原因。-Wconversion
的gcc文档中写道:
对可能更改值的隐式转换发出警告。这包括实数和整数之间的转换,如
x
为双时的abs (x)
;有符号和无符号之间的转换,如unsigned ui = -1;
,以及到较小类型的转换,例如sqrtf (M_PI)
。对于像abs ((int) x)
和ui = (unsigned) -1
这样的显式强制转换,或者如果像abs (2.0)
这样的转换没有更改值,请不要发出警告。可以使用-Wno-sign-conversion
禁用有关有符号整数和无符号整数之间转换的警告。对于C++,还要警告用户定义转换的重载解析混淆;以及从不使用类型转换运算符的转换:转换为
void
、相同类型、基类或对它们的引用。除非显式启用了-Wsign-conversion
,否则C++中默认情况下会禁用有关有符号整数和无符号整数之间转换的警告。
因此,这取决于您认为的"用户定义转换的混淆重载解决方案"。也许gcc开发人员认为A a{b}
看起来像是对A
构造函数的调用,因此他们认为调用B::operator A()
"令人困惑"。
或者它确实是一个bug。。。考虑到这似乎是一个很少使用的警告标志(它甚至不在-Wall中),并且考虑到"选择x而不是y"的消息是多么奇怪,这是很有可能的。
- cppcheck在const std::string[]上引发警告
- 将std::string传递给WriteConsole API
- 为std::string的某个索引赋值
- std中有类似find_last_of的函数,而string中没有
- 使用 std::string () const 函数启动线程或未来
- 当我们进行一些操作时,应该使用什么'std::string'或'std::stringstream'?
- 如何更改大小(std::string)
- std::string 的对象真的可以移动吗?
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- 无法从 std::string 中提取C++ Unicode 符号
- std::string 构造函数如何处理固定大小的 char[]?
- 确切地说,如何解释 std::getline(stream, string) 函数在C++中填充的字符串
- C++:考虑C++ std::string 中双引号 (") 的字面含义,而不使用反斜杠 (\)
- 'int main(int, int, std::__cxx11::string, std::__cxx11::string)'只需要零或两个参数 [-Wmain]
- C++ 在列表和列表之间选择返回类型<<string>std::p air<string,string>>
- std::string, std::wstring and UTF8
- uan inplace replacement of std::string/std::wstring?
- #define Glib::string std:wstring
- 从 std::string & std::wstring 中获取 char 整数值
- BSTR转换为std::string(std::wstring),反之亦然