|
Yes, the way it works in CString is bogus. I've been correcting my code as you suggest, adding (const char*), but it's got me wondering what's optimal?
- (const char*) won't work for UNICODE.
- (const TCHAR*) or (LPCTSTR) are MS specific.
- (const wchar_t*) doesn't work. why not?
Is there a standard-ish type or define for a single portable character? I thought wchar_t was.
Tom
|
|
|
|
|
...is to call c_str(). That will work for everything and is very portable.
Rememember, however, you'll still have to specify the correct format specifier (%s or %S), depending on whether you're using a "thin", char-based string (derived from std::string) or a wide, wchar_t-based string (derived from std::wstring.
-Joe
|
|
|
|
|
The principal problem with std::basic_string<> is the memory management.
Example:
CStdString str("hello ! ");
str += "I don't know ";
str += "what this message means.";
Here, there is 5 memory operations:
- allocate a buffer of characters to hold the string "hello !".
- free the buffer.
- reallocate it and fill it with "hello ! I don't know ".
- free it.
- reallocate it and fill it with "hello ! I don't know what this message means.".
We can do better in memory management:
- we use a class named CStdString which don't support any concatenation operations.
- we use a class named CStdStringList which support concatenation (it is a list of TCHAR*s).
So, we can also write:
CStdStringList strlist("hello !");
strlist += "I don't know ";
strlist += "what this message means.";
|
|
|
|
|
On the contrary. What you have stated is not necessarily true at all. It depends upon the implementation of basic_string.
Consider the case of the implementation that comes along with Visual Studio .NET. This version has a fixed buffer size of 16 characters. Only if the string length exceeds this size does any dynamic memory allocation occur.
So using your example code with this particular implementation:
CStdString str("hello ! ");<br />
str += "I don't know ";<br />
str += "what this message means.";
There would NOT be any allocation or freeing of memory for either of the first two lines. Only for the third one.
This is far simpler and more portable than going to the trouble of writing and debugging your own string classes just to deal with such a relatively uncommon situation. New programmers do not have to learn how YOU tihnk a string class' interface should be, they can simply use the same basic_string interface they have always used with an optimized implementation that takes care of most of the common inefficiencies. Also, they can be far more confident of thoroughly debugged code as the user base for the basic_string<> implementation is guaranteed to be larger than the user base for your string class.
Furthermore, if memory allocation is a bottleneck in your program the thing to do is not to write your own string class. Instead you should write your own, specialized allocator<> template which optimizes away such problems. Supply this allocator as an argument to the instantiation of the basic_string (or to CStdStr) template. This is why the designers of the Standard C++ Library added the concept of allocators in the first place. It is whole lot easier and safer to use your own allocator<> than it is to try to use your own custom string class. Take my word for it, after 6 years of supporting this CStdString code base, there are few people more acutely aware of this fact than I.
Finally, the major performance bottleneck in most programs these days is not string manipulation. Even reasonably well-written code (with at least a passing thought given towards avoiding inefficient multiple concatenation steps such as those in the example) will have no problems with string-related memory allocation.
-Joe
|
|
|
|
|
No biggie, but I get the following warnings in VS7.1...
h:\Dev\Common\StdString.h(2907) : warning C4018: '>' : signed/unsigned mismatch ...
h:\Dev\Common\StdString.h(2910) : warning C4018: '>' : signed/unsigned mismatch
h:\Dev\Common\StdString.h(2914) : warning C4018: '<=' : signed/unsigned mismatch
So I added this pragma to the beginning of your file.
#pragma warning( disable : 4018 )
Thanks,
Tom
|
|
|
|
|
I think I have since corrected these warnings. If not, the way for me to fix them is not to use a #pragma. Instead I should apply the appropriate static_cast<> to the mismatch areas.
Please let me know if downloading the latest version solves your problem. If not I must fix it. You can get the latest version here:
http://www.joeo.net/code/StdString.zip
I'm using Visual Studio .NET (albeit an old version) but I am not seeing these warnings)
-Joe
|
|
|
|
|
Yes, I am using the latest version. The file modify date is 13May03, but internally the last revision is 2003-MAR-14.
|
|
|
|
|
Actually, I just downloaded the most recent version and am seeing the problems. I use VS .NET 2002 (the "original" version.) I am not sure if it has anything to do with the warning level setting?
"When a man sits with a pretty girl for an hour, it seems like a minute. But let him sit on a hot stove for a minute and it's longer than any hour. That's relativity." - Albert Einstein
|
|
|
|
|
I'm using VS 7.0 and I don't see these warnings, even with the latest version. Could you post the exact line numbers you get with the new version. No doubt it's just a static_cast<> needed somwhere but I'd like to be sure.
-Joe
|
|
|
|
|
When compling in BCB 6.0 there come the errors:
1.[C++ Error] StdString.h(2666): E2268 Call to undefined function 'ssnprintf'
2.[C++ Error] StdString.h(1576): E2227 Extra parameter in call to isspace(int)
I use the class as following:
1.
CStdString str;
int iID = 1000;
str.Format("%d", iID);
2.
CStdString str = " Good! ";
str.Trim();
What's wrong?Please help!Thanks!
|
|
|
|
|
There is nothing wrong with your code. The problem is in my preprocessor flags. I've got a check for _MSC_VER in there that doesn't belong and I've got to remove and test it. I added it in recently while incorporating some changes from someone else designed to make the code work on another platform. The problem with making such changes is that I am unable to then re-test the code on all other platforms -- leading to problems such as this one.
I'll post back here in a day or two when I fix it. Sorry.
-Joe
|
|
|
|
|
First, thx for this great piece of work !
I don't know if you plan to be strictly compliant to CString or if you plan to extend your class to new methods and functionalities.
Anyway I found useful to add it some stuff like :
- the Tokenize function of the ATL strings :
MYTYPE Tokenize(PCMYSTR tok, int &nFirst) const
{
int nPrev;
if ( nFirst < 0 )
nFirst = 0;
if ( nFirst >= size() )
return MYTYPE();
nPrev = nFirst;
nFirst = this->find_first_of(tok, nPrev);
if (nFirst == npos)
nFirst = size();
return this->substr(static_cast<mysize>(nPrev), static_cast<mysize>(nFirst++ - nPrev));
}
- and conversion stuff between primary types and strings :
operator const int() const
{
return atoi(c_str());
}
operator const unsigned int() const
{
return atoi(c_str());
}
operator const long() const
{
return atol(c_str());
}
operator const unsigned long() const
{
return atol(c_str());
}
operator const __int64() const
{
return _atoi64(c_str());
}
operator const unsigned __int64() const
{
return _atoi64(c_str());
}
operator const double() const
{
return atof(c_str());
}
CStrEx(int i)
{
Format("%d", i);
}
CStrEx(unsigned int ui)
{
Format("%u", ui);
}
CStrEx(long l)
{
Format("%ld", l);
}
CStrEx(unsigned long ul)
{
Format("%lu", ul);
}
CStrEx(__int64 i64)
{
Format("%i64d", i64);
}
CStrEx(unsigned __int64 ui64)
{
Format("%ui64u", ui64);
}
CStrEx(double d)
{
Format("%g", d);
}
Ok, I admit the constructors are notessential
|
|
|
|
|
BTW, I renamed your class to CStringEx for my own use
(sounds better to me )
but you keep all credits in the header comments don't worry
|
|
|
|
|
Hi,
I'm glad you got good use out of the class.
The main reason I don't add conversion operators and constructors such as the ones you mentioned is that they lead to unintended side effects. Read up on Scott Myers for more on this subject but the basic message is "avoid user-defined conversion operators whenever possible."
I've even had to fight the debate over the one user-defined conversion that I DID put in there -- operator const CT* -- which just calls c_str(). There is no such operator in basic_string due to the dangers I mentioned above. But I was so used to it from CString that I simply had to have it. The convenience is more than worth what is a minor risk, IMHO. Just be aware that some C++ purists do not like that.
Still the argument against conversion operators is a very sound one. In the very least, those constructors you mentioned should be declared with the "explicit" keyword.
Anyway at this point the class is almost 7 years old. As I have tried to keep it working on all platforms (Windows, Unix, Linux, Solaris, etc) I have basically reached the point where I do not want to add any more functions to it. It is tough enough to keep it working. In fact, right now I'm working on a fix for "billca" (see the recent feedback below).
But you are of course free to add or change anything you want. I'd still recommend against those operators and constructors, but hey, go crazy.
Please let me know if you have any problems.
-Joe
|
|
|
|
|
Joe, in your comments within the function ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl), you say you'd like to hear about compile errors related to the various versions of vswprintf on the various platforms. In order to get a clean compile on HP-UX and LINUX, I changed:
#if (!defined(_MSC_VER) &&
!defined (__BORLANDC__) &&
!defined(__GNUC__) &&
!defined(__sgi)
to
#if (!defined(_MSC_VER) &&
!defined (__BORLANDC__) &&
!defined(__GNUC__) &&
!defined(__sgi) &&
!defined(HPUX1100)) ||
defined(LINUX)
and
#elif defined(__sgi)
to
#elif defined(__sgi) || defined(HPUX1100)
I don't know if these new definitions would be the right ones to be used generally, but they seem to work for my installation.
Bill
|
|
|
|
|
This is great stuff. And I have no way of knowing it since all I've got right now is a Windows box. I will definitely add this in to the preprocessor headers on the on-line version. You get a big credit in the header for this (and for all the other stuff you're helping out with here).
I'll try to coordinate with you off-line testing all the changes I've made once we get all these matters resolved and I'll post a new version soon.
Thanks!
-Joe
|
|
|
|
|
Joe, since CStdString doesn't claim to be exactly the same as CString and since CString of course doesn't even work at all on the UNIX platforms that CStdString does, I'm not sure the following should be considered a problem with CStdString, and I don't know if you'll want to change anything, but it certainly is an additional pitfall that one should be aware of when using CStdString in place of CString. Using a simple example, with UNICODE defined, say you code something like:
mystring1.Format(L"%s", (const wchar_t*)mystring2);
With CString, the %s (lower case) format specification is correct as it is with CStdString on Windows, but using CStdString and running on Solaris (and probably other UNIXs too), it needs to be %S (upper case). The underlying vswprintf function apparently expects it that way.
So for platform-independence, rather than have two versions of every Format call, I couldn't think of anything else but to leave the %s(s) and make the necessary adjustment inside StdString.h as follows:
In ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl), after the #if !defined(_MSC_VER)..., I replaced
return vswprintf(pW, nCount, pFmtW, vl);
with
std::basic_string<wchar_t> pFmtW2 = pFmtW;
std::basic_string<wchar_t>::size_type index = 0;
while ((index = pFmtW2.find(L"%s", index)) != std::basic_string<wchar_t>::npos)
{
pFmtW2.replace(index + 1, 1, L"S");
index += 2;
}
return vswprintf(pW, nCount, pFmtW2.c_str(), vl);
I realize this is a bit of a kludge and you may not want to do anything like it in the real thing, but I thought you should know and I'd be interested in your thoughts.
Bill
|
|
|
|
|
Hi Bill,
My general thoughts here are not to try to do this. I have two reasons. One is a philosophical one, and the other a practical one.
The philosophical reason for not making the change is this: In essence, what you are doing is trying to protect the programmer from himself (or herself). What he/she is doing here is violating a rule of C++. The Format() function has always been just a thin veneer or sprintf/vswprintf. That was always clear, even from CString. The only convenience it is supposed to add is doing the memory/buffer management for you. THAT is the part that is truly a pain with sprintf. Admittedly, I have made such a protect-them-from-themselves change myself with the entire SS_SAFE_FORMAT fix I put in there. But my fix is completely unobtrusive, adds no danger, and can be disabled via macro. Furthermore, having made such a change once, I hope never to have to do so again.
The practical reason is that your solution might actually mess up valid code. Let's take your example
mystring1.Format(L"%s", (const wchar_t*)mystring2);
and change it to the following
mystring1.Format(L"%s %S", *)"this is a thin string", L"and this is a wide string");
In this case, the programmer intends the first '%s' to be a lowercase 's' because the string argument he/she supplied was a char-based string constant. If Format() were to change this to '%S' it would cause a problem.
And since those two string literal arguments at the end of the function call in this example are part of the variable argument list, there is no way for the compiler to know what they really are. We have no way of divining the programmers intentions except through the format specifiers themselves. If we cannot rely on THOSE being correct then we might as well throw in the towel.
So that is why I would hesitate to make this change.
-Joe
|
|
|
|
|
For what it's worth, I too have thought all along that you probably shouldn't change any code for this, but to me the issue is perhaps a bit more significant than I gather you're thinking, and noteworthy (whether for documentation or just in your mind) if only because I think others will inevitably and innocently fall into this trap. I probably didn't explain my thoughts clearly enough at first as to why I think it's significant -- or at least interesting. Not to try to persuade any action on your part, but just as explanation and at the risk of boring you...
As I said, although you don't claim that CStdString is exactly the same as CString, the fact is that one can take an MFC application, change the CStrings to CStdStrings and (aside from some possible tweaks for compilation purposes) run it on UNIX -- this is what makes CStdString so great. Other than the StdCodeCvt problem you and I are currently discussing elsewhere, this is the only runtime issue I have encountered related to CString/CStdString replacement that requires changes to my applications (well, since I decided not to use SS_SAFE_FORMAT, I also had some changes to make related to that), which alone makes this issue special. And when first addressing the issue, it's particularly hard to figure out -- there's no crash, the strings just don't get formatted correctly. Considering it purely from this angle -- as a replacement for CString -- it is very much like your SS_SAFE_FORMAT issue, as you pointed out.
With the vs(n)printf and vs(n)wprintf functions on Windows, which I assume the CString Format function uses or at least emulates, '%s' means a thin string and '%S' means a wide string for vsprintf, but the opposite for vswprintf where '%s' means wide and '%S' thin! Apparently CString.Format works the same way. So with UNICODE defined, '%s' means the argument is a *wide* string. And with UNICODE not defined, the same symbol, '%s', means *thin* string. So the application code stays the same (i.e. lower case 's') whether built for UNICODE or not, which is nice. The only time you would use '%S' with CString is when you had a string argument that is opposite in thinness/wideness from the CString itself. Incidently, while the point made by your counter example is well-taken, the implication is that the example would not be correct if mystring1 were a UNICODE-enabled CString (the format symbols would need to be reversed) -- maybe you realize this and didn't intend to say anything to the contrary.
Now with CStdString -- and running on UNIX (Solaris, at least) -- this is NOT the case. Granted, CString doesn't even work at all on UNIX (otherwise I suppose it would have to deal with this same issue), so understandably CStdString is taking on a much bigger burden. But because the underlying vswprintf function on UNIX (unlike the Windows version, for whatever reason) expects '%S' for wide strings, all the Format '%s's in a UNICODE-enabled application would need to be changed to '%S'.
Now I chose to leave all the Format '%s's in my application code as lower case and programmatically convert them to '%S' inside the ssvsprintf function (as well, I suppose, for consistency change any '%S's to '%s'). But as you pointed-out of course this only works when you assume there are no Format calls, in a UNICODE-enabled application, that include a thin string argument with the "correct" (correct for UNIX, that is) symbol, '%s'. For me this won't happen because all my CStdString.Format calls (mostly former CString.Format ones -- and a few new ones) are coded the CString way. So in the unlikely event I ever did include a thin string argument, I would use the '%S' symbol and it would ultimately be handled correctly.
And so my point is simply that this issue, which I tend to think would be encountered by many, and the subsequent changes required, is significant because it is really the one and only hindrance to what is otherwise a practically flawless CString/CStdString migration.
Bill
|
|
|
|
|
Joe, running on Solaris I came across what appears to be a problem with the source-length parameter on the StdCodeCvt call in seven out of the eight ssasn and ssadd functions in which this call is made. (Curiously, although these eight functions are similar and are otherwise coded consistently, the odd one, that does seem to work properly as is, has the source-length parameter inconsistent with the others.) In each instance, an assertion in StdCodeCvt fails, then the program crashes with "Error 115 Unexpected signal (Signal 6)". The exact lines in question, and what I did to correct them, are indicated below in the comments of a simple program I used to test each of the assignment/concatenation functions. If you don't think these changes were the right thing to do or if you have any questions/comments, please let me know.
#include "StdString.h"
int main()
{
CStdString ansiStdString = L"";
// With UNICODE not defined, this line causes:
//
// Assertion failed: (SSCodeCvt ::ok == res)
// in StdCodeCvt(PSTR pA, PCWSTR pW, int nChars, const std::locale& loc=std::locale()).
//
// Corrected by changing
//
// StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), pW, nLen);
//
// to
//
// StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), pW, nLen+1);
//
// in ssasn(std::string& sDst, PCWSTR pW).
std::basic_string<wchar_t> wideBasicString = L"";
ansiStdString = wideBasicString;
// With UNICODE not defined, this line causes:
//
// Assertion failed: (SSCodeCvt ::ok == res)
// in StdCodeCvt(PSTR pA, PCWSTR pW, int nChars, const std::locale& loc=std::locale()).
//
// Corrected by changing
//
// StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);
//
// to
//
// StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen+1);
//
// in ssasn(std::string& sDst, const std::wstring& sSrc).
ansiStdString += wideBasicString;
// With UNICODE not defined, this line causes:
//
// Assertion failed: (SSCodeCvt ::ok == res)
// in StdCodeCvt(PSTR pA, PCWSTR pW, int nChars, const std::locale& loc=std::locale()).
//
// Corrected by changing
//
// StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDstLen), sSrc.c_str(), nSrcLen);
//
// to
//
// StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDstLen), sSrc.c_str(), nSrcLen+1);
//
// in ssadd(std::string& sDst, const std::wstring& sSrc).
CStdString wideStdString = "";
// With UNICODE defined, this line causes:
//
// Assertion failed: (SSCodeCvt ::ok == res)
// in StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, const std::locale& loc=std::locale()).
//
// Corrected by changing
//
// StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), pA, nLen+1);
//
// to
//
// StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), pA, nLen);
//
// in ssasn(std::wstring& sDst, PCSTR pA).
wideStdString += "";
// With UNICODE defined, this line causes:
//
// Assertion failed: (SSCodeCvt ::ok == res)
// in StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, const std::locale& loc=std::locale()).
//
// Corrected by changing
//
// StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDstLen), pA, nSrcLen+1);
//
// to
//
// StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDstLen), pA, nSrcLen);
//
// in ssadd(std::wstring& sDst, PCSTR pA).
std::basic_string<char> ansiBasicString = "";
wideStdString = ansiBasicString;
// With UNICODE defined, this line causes:
//
// Assertion failed: (SSCodeCvt ::ok == res)
// in StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, const std::locale& loc=std::locale()).
//
// Corrected by changing
//
// StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen+1);
//
// to
//
// StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);
//
// in ssasn(std::wstring& sDst, const std::string& sSrc).
wideStdString += ansiBasicString;
// With UNICODE defined, this line causes:
//
// Assertion failed: (SSCodeCvt ::ok == res)
// in StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, const std::locale& loc=std::locale()).
//
// Corrected by changing
//
// StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDstLen), sSrc.c_str(), nSrcLen+1);
//
// to
//
// StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDstLen), sSrc.c_str(), nSrcLen);
//
// in ssadd(std::wstring& sDst, const std::string& sSrc).
return 0;
}
Bill
|
|
|
|
|
Hi Bill,
This looks like a lot of work you've done in this one and I appreciate it. But I think that what you have done, while it works, it perhaps not the best solution.
Before I explain why, I have two questions. I don't have Solaris so I can't try this. It would greatly help me to be sure if I understand the problem correctly. This is vital to me because it seems every time I correct a bug on one platform, I cause one on another. I need to be sure I truly understand what the problem is.
To answer these you will need the original, uncorrected version of StdString.h:
1. Do you know what value codecvt::in was returning when it was giving you the error? I'm referring to your very first example here. I was ASSERTing that it should equal codecvt::ok but I suspect that in your case it instead equalled something like codecvt::partial. It would help if I knew.
2. Take your first example that was causing your problems (with UNICODE defined) and change it from this:
CStdString ansiStdString = L"";
to this:
CStdString ansiStdString = L"Hello";
Does the ASSERT still fail? My guess is that it will not but I need to know for sure.
To illustrate why, let's take a look at the overload of StdCodeCvt which is being called:
<br />
inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars,<br />
const std::locale& loc=std::locale())<br />
{<br />
ASSERT(0 != pA);<br />
ASSERT(0 != pW);<br />
pA[0] = '\0';<br />
PSTR pBadA = 0;<br />
PCWSTR pBadW = 0;<br />
SSCodeCvt::result res = SSCodeCvt::ok;<br />
const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);<br />
SSCodeCvt::state_type st= { 0 };<br />
res = conv.out(st,<br />
pW, pW + nChars, pBadW,<br />
pA, pA + nChars, pBadA);<br />
ASSERT(SSCodeCvt::ok == res);<br />
return pA;<br />
}<br />
The 'nChars' argument is used in pointer arithmetic. I am using it to tell the codecvt::in function where the source string's null terminator character is -- it is 'nChars' characters past the beginning.
In the example you used, the source string was empty so the first character was the null terminator. But by changing that length to 1, you have effectively told the codecvt::in function to look past even the null terminator. That is not a valid thing to do but I suspect we're just "getting away with it".
My suspicion is that the real problem lies in the fact that I'm calling codecvt::in (or codecvt::out on the other examples) on a zero-length string. I suspect that what I should really be doing is having a special case which checks for zero-length strings and does nothing.
Hope this is clear. Again I appreciate your effort in this
-Joe
|
|
|
|
|
1. Yes, the original way returns codecvt::partial.
2. What you say makes sense and you're right about the first example -- it only ASSERTS (and crashes) with an empty string. In fact, the same is true for examples 1, 2 and 3 (call this group Case 1). This is consistent in that these are the three that convert from wide to ansi and are the ones that I got to work by passing length+1 instead of length. However, the last four examples (call them Case 2) still fail the same way whether the source string is empty or not. (These four are opposites of the others in that they convert from ansi to wide and only work when you pass length instead of length+1.)
So, I agree with your assessment of the right way to handle Case 1...which leaves Case 2.
By the way if you haven't noticed already, the "odd" one of the eight related functions, which is missing from the examples due to it working as is (namely ssadd(std::string& sDst, PCWSTR pW)), essentially belongs to Case 1 and only works now because it passes length+1 (which is what prompted me to change the others the way I did)! So whatever we wind up doing, you should probably make this one consistent with the other Case 1 functions.
Bill
|
|
|
|
|
I got the impression you were going to make a fix for this (with my help for testing if necessary), but I haven't heard anything from you in a while nor seen any related change to your latest source. Are you still planning to address this? Thanks and let me know if you need any help from me.
Bill
|
|
|
|
|
Unfortunately this seems to have opened a can of worms for me regarding how I do conversions. But admittedly, I've dragged my feet here.
I'll email you directly about this and we can figure it out.
-Joe
|
|
|
|
|
I have just been fighting a strange bug in an VC++ 6.0 Win32 Console App, where I wanted to use CStdString - the 14. MAR 2003 version.
In addition, I use the 3.08 version of Dinkumware STL. I had several
"error C2039: 'std' : is not a member of 'std'".
It turned out to be related to the SS_USE_FACET-definition.
#ifndef SS_USE_FACET<br />
#if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )<br />
#if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)<br />
#ifdef SS_ANSI<br />
#pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)<br />
#endif<br />
#endif<br />
#define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)<br />
#elif defined(_MSC_VER )<br />
#define SS_USE_FACET(loc, fac) std::_USE(loc, fac)<br />
<br />
#elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)<br />
#define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)<br />
#else<br />
#define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)<br />
#endif<br />
#endif
I emphasized the string where I had problems, and by changing this line to
#define SS_USE_FACET(loc, fac) _USE(loc, fac)
(I removed the std:: namespace specifier just before _USE...), I could compile without trouble.
I have no idea if this is "smart" to do. Any comments ?
Bob
Proud Programmer!
|
|
|
|
|