尝试在库中添加对UTF-8语言环境的支持时,我补充道
保存值的std::wstring
类型boost::variant
。
此时,我开始在boost::variant
内发现错误:
Blockquote / opt / TWWfsw / libboost147 / include / boost / variant / detail / variant_io.hpp:在成员函数'void boost :: detail :: variant :: printer :: operator()(const T&)const [使用T = std :: basic_string,std :: allocator>,OStream = std :: basic_ostream>]':
/opt/TWWfsw/libboost147/include/boost/variant/variant.hpp:858:从'typename Visitor :: result_type boost :: detail :: variant :: invoke_visitor :: internal_visit(T&,int)实例化[with T = const std :: basic_string,std :: allocator&gt ;, Visitor = boost :: detail :: variant :: printer> >]'
< SNIP SNIP>
Cursor.H:84:从这里实例化 /opt/TWWfsw/libboost147/include/boost/variant/detail/variant_io.hpp:64:错误:不匹配'operator<<'在'((const boost :: detail :: variant :: printer>> )this) - > boost :: detail :: variant :: printer> > :: out_<<操作数“
/ opt / TWWfsw / gcc44 / include / c ++ / ostream:108:注意:候选人是: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]
等。
此示例使用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,它也不会编译。
答案 0 :(得分:3)
您的问题不是boost::variant
无法处理string
和wstring
。问题是wcout
无法处理std::string
。有关此问题的详细信息,请参阅Why is it that wcout << ""; is OK but wcout << string(); is not?
答案 1 :(得分:1)
以@John Bandela的回答为基础:他实际上是正确的。我只是解释一下罪魁祸首。
请注意std::cout << std::string()
和std::wcout << std::wstring()
有效,而std::wcout << std::string()
和std::wcout << std::string()
则不然。这只是由于流操作符的定义(参见Why is it that wcout << ""; is OK but wcout << string(); is not?)除非您提供处理此操作的重载,否则根本不可能。
同样适用于变体:如果您尝试将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
中)并且只在边界点转换。