static_cast<std::u16string> 的 GCC 问题
Posted
技术标签:
【中文标题】static_cast<std::u16string> 的 GCC 问题【英文标题】:GCC problem with static_cast<std::u16string> 【发布时间】:2018-10-17 09:01:15 【问题描述】:总结
我有一个类,我添加了一个类型转换运算符以转换为std::u16string
。该运算符的签名如下所示:
operator const std::u16string() const;
在我的 .cpp 文件中,我尝试将我的类类型的对象转换为 std::u16string
,如下所示:
std::u16string sUTF16Password = static_cast<std::u16string>(Password_);
在 Visual Studio 2017 上,这工作得很好。但是,我的 Raspberry Pi 上的 GCC 6.3 在编译时会出现以下错误:
error : call of overloaded 'basic_string(MyClass&)' is ambiguous
编写此类型转换的正确方法是什么?在 Google 上搜索为字符编码转换带来了很多成功,但这不是我的问题。我不明白为什么尽管使用了static_cast
,但这里还是调用了basic_string
构造函数。
完整示例
这是一个最小的例子。在我的 Raspberry Pi 上使用 g++ main.cpp
编译它失败。
#include <iostream>
#include <string>
class MyClass
private:
std::u16string Str;
public:
MyClass() Str = u"abcd";
operator const char16_t*() const return Str.c_str();
operator std::u16string() const return Str;
;
int main()
MyClass Tester;
std::u16string TestStr = static_cast<std::u16string>(Tester);
for (size_t idx = 0; idx < TestStr.size(); idx++)
std::cout << idx << ": " << TestStr[idx] << std::endl;
return 0;
gcc --version
的输出是gcc (Raspbian 6.3.0-18+rpi1+deb9u1) 6.3.0 20170516
。
g++ main.cpp
的完整输出为:
main.cpp: In function ‘int main()’:
main.cpp:17:61: error: call of overloaded ‘basic_string(MyClass&)’ is ambiguous
std::u16string TestStr = static_cast<std::u16string>(Tester);
^
In file included from /usr/include/c++/6/string:52:0,
from /usr/include/c++/6/bits/locale_classes.h:40,
from /usr/include/c++/6/bits/ios_base.h:41,
from /usr/include/c++/6/ios:42,
from /usr/include/c++/6/ostream:38,
from /usr/include/c++/6/iostream:39,
from main.cpp:1:
/usr/include/c++/6/bits/basic_string.h:476:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_
CharT, _Traits, _Alloc>&&) [with _CharT = char16_t; _Traits = std::char_traits<char16_t>; _Alloc = std::allocator<char16_t>]
basic_string(basic_string&& __str) noexcept
^~~~~~~~~~~~
/usr/include/c++/6/bits/basic_string.h:454:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&
) [with _CharT = char16_t; _Traits = std::char_traits<char16_t>; _Alloc = std::allocator<char16_t>]
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
^~~~~~~~~~~~
/usr/include/c++/6/bits/basic_string.h:397:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_st
ring<_CharT, _Traits, _Alloc>&) [with _CharT = char16_t; _Traits = std::char_traits<char16_t>; _Alloc = std::allocator<char16_t>]
basic_string(const basic_string& __str)
^~~~~~~~~~~~
如果我将类型转换删除为const char16_t*
,则此示例编译得很好。我仍然不明白为什么同时使用两种类型转换是个问题。
【问题讨论】:
哦,顺便说一句,通过const
值返回任何东西都是无用的,因为调用者可能仍将值存储在非常量变量中。
刚刚尝试不使用第一个 const,即operator std::u16string() const
,但这对错误没有影响。
错误的原因是basic_string
有一个构造函数接受CharT*
,因此std::u16string
可以从char16_t const*
构造。因此,编译器无法确定应该调用这两个运算符中的哪一个。
@MariusBancila VC++(它不会抱怨)是否违反了 C++ 标准?
它确实抱怨;至少 VC++ 2017。运行示例会导致错误 C2440: 'static_cast': cannot convert from 'MyClass' to 'std::u16string' note: No constructor could take the source type, or constructor overload resolution was ambiguous
【参考方案1】:
如果你编译为 C++14(或更早版本),你会得到这个模棱两可的调用,因为std::u16string(char16_t*)
参与了重载决议(通过MyClass::operator const char16_t*()
)以及MyClass::operator std::u16string()
会似乎更合适。
这可以通过多种方式克服:
使用 GCC 7 或更高版本编译为 C++17(或更高版本)(遗憾的是,这对 GCC 6 没有帮助)。 删除operator const char16_t*()
。
将explicit
添加到operator const char16_t*()
(或添加到两个转换运算符)。
【讨论】:
以上是关于static_cast<std::u16string> 的 GCC 问题的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 wstring_convert 在 utf16 和 utf32 之间进行转换?