Boost::variant不能同时处理string和wstring
boost::variant can not handle string and wstring together
在尝试在库中添加对UTF-8区域设置的支持时,我添加了
将类型std::wstring
转换为保存值的boost::variant
。在这一点上,我开始得到错误的东西在boost::variant
:
Blockquote/opt/TWWfsw/libboost147/include/boost/variant/detail/variant_io.hpp: In member function 'void boost::detail::variant::printer<OStream>::operator()(const T&) const [with T = std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >, OStream = std::basic_ostream<char, std::char_traits<char> >]':<BR>
/opt/TWWfsw/libboost147/include/boost/variant/variant.hpp:858: instantiated from 'typename Visitor::result_type boost::detail::variant::invoke_visitor<Visitor>::internal_visit(T&, int) [with T = const std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >, Visitor = boost::detail::variant::printer<std::basic_ostream<char, std::char_traits<char> > >]'<BR>
< SNIP SNIP ><BR>
Cursor.H:84: instantiated from here
/opt/TWWfsw/libboost147/include/boost/variant/detail/variant_io.hpp:64: error: no match for 'operator<<' in '((const boost::detail::variant::printer<std::basic_ostream<char, std::char_traits<char> > >*)this)->boost::detail::variant::printer<std::basic_ostream<char, std::char_traits<char> > >::out_ << operand'<BR>
/opt/TWWfsw/gcc44/include/c++/ostream:108: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]<BR>etc.
本例使用boost-1.47 w/g++ 4.4。
#include <string>
#include <iostream>
#include <boost/variant.hpp>
#define NO_STRING 1
int main (int argc, char** argv)
{
#if defined(NO_STRING)
boost::variant<int, std::wstring> v;
#else
boost::variant<int, std::wstring, std::string> v;
#endif
v = 3;
std::wcout << v << std::endl;
std::wstring T(L"wide char literal");
v = T;
std::wcout << v << std::endl;
return 0;
}
程序将输出:
3
宽字符字面值
但如果去掉#define
,并且string
和wstring
都在不同的模板参数中,则产生相同的错误。
我的问题是,我可以创建一些东西来满足这个缺失的定义,比如模板专门化吗?
可以定义一个将宽字符串转换为窄字符串的变体访问器吗?(不是一般的解决方案,但缩小在我的情况下会工作)
问题来自于在定义了两个字符串时使用<<
和变体。即使我只通过变量输出int,它也不会编译。
你的问题不是boost::variant
不能处理string
和wstring
。问题是wcout
不能处理std::string
。有关这方面的更多信息,请参阅为什么会出现这种情况<<";还可以,但是我要离开<<字符串();不是吗?
基于@John Bandela的回答:他实际上是对的。
我要多解释一下这个罪魁祸首。注意std::cout << std::string()
和std::wcout << std::wstring()
是有效的,而std::wcout << std::string()
和std::wcout << std::string()
是无效的。这仅仅是由于流操作符的定义(参见为什么wcout <<";还可以,但是我要离开<<字符串();不是吗?)这是不可能的,除非你提供一个重载来处理它。
同样适用于变量:如果您尝试将variant<std::string>
流到std::wcout
或variant<std::wstring>
流到std::cout
,您将得到相同的错误。
问题的根本在于:应用于变量的操作(访问、流操作符)必须支持所有可能包含的类型。这是由于实现类似于(伪代码):
void variant::visit(T operation){
if(contained is T1) operation(static_cast<T1>(contained));
else if(contained is T2) operation(static_cast<T2>(contained));
...
}
所以你的问题的解决方案是:自己实现所有类型的操作:
#include <string>
#include <iostream>
#include <boost/variant.hpp>
std::wstring stringToWString(const std::string& v){
// Only works for single-byte strings. Do it better!
std::wstring result(v.begin(), v.end());
return result;
}
struct visitor: boost::static_visitor<void>{
template<typename T>
void operator()(const T& v) const { std::wcout << v; }
void operator()(const std::string& v) const { std::wcout << stringToWString(v); }
};
int main (int argc, char** argv)
{
boost::variant<int, std::wstring, std::string> v;
v = 3;
boost::apply_visitor(visitor(), v);
std::wcout << std::endl;
std::wstring T(L"wide char literal");
v = T;
boost::apply_visitor(visitor(), v);
std::wcout << std::endl;
v = std::string("Narrow string");
boost::apply_visitor(visitor(), v);
std::wcout << std::endl;
return 0;
}
http://coliru.stacked-crooked.com/a/35e156f38208af1e 最后注意:使用std::wstring
不支持UTF-8 ! UTF-8可以存储在常规的std::string
中。很少有地方需要将其转换为其他内容。其中之一是处理WinAPI。为此,您可以编写包装器,它接受std::string
并在将其传递给实际API之前进行转换。
所以一般的建议:在你的程序中使用UTF-8(在std::string
中),只在边界点转换
- 将日语 wstring 转换为 std::string
- 将utf16宽std::wstring转换为utf8窄std::string以获得罕见字符时出现问题
- 将 std::string 转换为具有特殊字符的 FString (TCHAR / wstring)
- UTF8 数据到 std::string 或 std::wstring
- 从相同的硬编码字符串文字初始化std::string和std::wstring
- C++ 字符串 - 如何为 wstring 实现此'IsEmptyOrSpace(string)'方法?
- 将 std::string 移植到 std::wstring,反之亦然
- 在std::string和std::wstring之间转换的多平台方式
- 将 wstring、string 和对枚举变量的引用从 C# 传递到 C++(非托管 DLL)
- C++ 对 MBCS 使用 std::string 函数,对 UTF-16 使用 std::wstring 函数
- std::string, std::wstring and UTF8
- C++将数据从 std::string 复制到 std::wstring
- 如何处理可能是 std::string 或 std::wstring 的值
- C++使用std::string、std::wstring作为缓冲区
- 当传递从std::string转换为wstring的路径时,CreateProcess失败
- uan inplace replacement of std::string/std::wstring?
- Custom Stringstream - Convert std::wstring & std::string
- #define Glib::string std:wstring
- 从 std::string & std::wstring 中获取 char 整数值
- std::string, wstring, u16/32string clarification