std::basic_stringstream<unsigned char> won't compile with MSVC 10
Posted
by
Michael J
on Stack Overflow
See other posts from Stack Overflow
or by Michael J
Published on 2012-06-18T02:08:21Z
Indexed on
2012/06/23
15:16 UTC
Read the original article
Hit count: 627
I'm trying to get UTF-8 chars to co-exist with ANSI 8-bit chars. My strategy has been to represent utf-8 chars as unsigned char
so that appropriate overloads of functions can be used for the two character types.
e.g.
namespace MyStuff
{
typedef uchar utf8_t;
typedef std::basic_string<utf8_t> U8string;
}
void SomeFunc(std::string &s);
void SomeFunc(std::wstring &s);
void SomeFunc(MyStuff::U8string &s);
This all works pretty well until I try to use a stringstream.
std::basic_ostringstream<MyStuff::utf8_t> ostr;
ostr << 1;
MSVC Visual C++ Express V10 won't compile this:
c:\program files\microsoft visual studio 10.0\vc\include\xlocmon(213):
warning C4273: 'id' : inconsistent dll linkage
c:\program files\microsoft visual studio 10.0\vc\include\xlocnum(65) :
see previous definition of
'public: static std::locale::id std::numpunct<unsigned char>::id'
c:\program files\microsoft visual studio 10.0\vc\include\xlocnum(65) :
while compiling class template static data member 'std::locale::id
std::numpunct<_Elem>::id'
with
[
_Elem=Tk::utf8_t
]
c:\program files\microsoft visual studio 10.0\vc\include\xlocnum(1149) :
see reference to function template instantiation
'const _Facet &std::use_facet<std::numpunct<_Elem>>(const std::locale &)'
being compiled
with
[
_Facet=std::numpunct<Tk::utf8_t>,
_Elem=Tk::utf8_t
]
c:\program files\microsoft visual studio 10.0\vc\include\xlocnum(1143) :
while compiling class template member function
'std::ostreambuf_iterator<_Elem,_Traits>
std::num_put<_Elem,_OutIt>::
do_put(_OutIt,std::ios_base &,_Elem,std::_Bool) const'
with
[
_Elem=Tk::utf8_t,
_Traits=std::char_traits<Tk::utf8_t>,
_OutIt=std::ostreambuf_iterator<Tk::utf8_t,std::char_traits<Tk::utf8_t>>
]
c:\program files\microsoft visual studio 10.0\vc\include\ostream(295) :
see reference to class template instantiation 'std::num_put<_Elem,_OutIt>'
being compiled
with
[
_Elem=Tk::utf8_t,
_OutIt=std::ostreambuf_iterator<Tk::utf8_t,std::char_traits<Tk::utf8_t>>
]
c:\program files\microsoft visual studio 10.0\vc\include\ostream(281) :
while compiling class template member function
'std::basic_ostream<_Elem,_Traits> &
std::basic_ostream<_Elem,_Traits>::operator <<(int)'
with
[
_Elem=Tk::utf8_t,
_Traits=std::char_traits<Tk::utf8_t>
]
c:\program files\microsoft visual studio 10.0\vc\include\sstream(526) :
see reference to class template instantiation
'std::basic_ostream<_Elem,_Traits>' being compiled
with
[
_Elem=Tk::utf8_t,
_Traits=std::char_traits<Tk::utf8_t>
]
c:\users\michael\dvl\tmp\console\console.cpp(23) :
see reference to class template instantiation
'std::basic_ostringstream<_Elem,_Traits,_Alloc>' being compiled
with
[
_Elem=Tk::utf8_t,
_Traits=std::char_traits<Tk::utf8_t>,
_Alloc=std::allocator<uchar>
]
.
c:\program files\microsoft visual studio 10.0\vc\include\xlocmon(213):
error C2491: 'std::numpunct<_Elem>::id' : definition of dllimport
static data member not allowed
with
[
_Elem=Tk::utf8_t
]
Any ideas?
** Edited 19 June 2012 **
OK, I've gotten closer to understanding this, but not how to solve it.
As we all know, static class variables get defined twice:
- once in the class definition and
- once outside the class definition which establishes storage space.
e.g.
// in .h file
class CFoo
{
// ...
static int x;
};
// in .cpp file
int CFoo::x = 42;
Now in the VC10 headers we get something like this:
template<class _Elem>
class numpunct : public locale::facet
{
// ...
_CRTIMP2_PURE static locale::id id;
// ...
}
When the header is included in an application, _CRTIMP2_PURE
is defined as __declspec(dllimport)
, which means that the variable is imported from a dll.
Now the header also contains the following
template<class _Elem>
locale::id numpunct<_Elem>::id;
Note the absence of the __declspec(dllimport)
qualifier.
i.e. The class declaration says that the static linkage of the id
variable is in the dll, but for the general case, it gets declared outside the dll.
For the known cases, there are specialisations.
template locale::id numpunct<char>::id;
template locale::id numpunct<wchar_t>::id;
These are protected by #if
s so that they are only included when building the DLL. They are excluded otherwise.
i.e. the char
and wchar_t
versions of numpunct ARE inside the dll
So we have the class definition saying that id's storage is in the DLL, but that is only true for the char
and wchar_t
specialisations, meaning that my unsigned char version is doomed. :-(
The only way forward that I can think of is to create my own specialisation: basically copying it from the header file and fixing it. This raises many issues.
Anybody have a better idea?
© Stack Overflow or respective owner