Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Problem with my string template class and Windoze ANSI and UNICODE strings?

42 views
Skip to first unread message

DSF

unread,
Oct 11, 2014, 3:09:35 PM10/11/14
to
Hello group!

So far, my string template class has been working well. It's based
on this code to select 8-bit or 16-bit strings:

template <class CH> class FString
{
...
}

typedef FString<char> FStringA;
typedef FString<wchar_t> FStringW;

#ifdef UNICODE
#define FString FStringW
#else
#define FString FStringA
#endif

I've thought of a problem. Let's say UNICODE is defined,
FString str;
will create a wide string. But I create temporary FStrings within the
class. As I see it, when,
FString tmpstr;
is encountered it will create a wide string. But say whilst in
UNICODE mode, I create an explicit ANSI FString,
FStringA ansistr;
If I'm right the temporaries created within ansistr will be wide, as
per the above typedefs and defines.

I just tested my theory and it's false. A temporary FString within
the FString class follows the type of CH. I assume that is because a
FString created within the class "<class CH> class FString" already
knows what it is. It doesn't use the exterior typedefs and
definitions.

I almost dumped this whole post, but I am curious if I am right and
I have another question.

When defining a member function outside a template class
declaration, one uses FString<CH>::Function instead of the
non-template FString::Function. I've found myself using the same in
the parameter list:
template <class CH> FString<CH>::FString(const FString<CH>& string);
Or within a member function to construct a new FString:
FString<CH> tfs(p, cs);

But this works equally well:
template <class CH> FString<CH>::FString(const FString& string);
FString tfs(p, cs);

Does it matter either way? I do know it's necessary in a construct
like this:
(Within declaration)
friend bool operator==(const FString<CH>& str1, const FString<CH>&
str2);

(Outside declaration)
template <class CH> inline bool operator==(const FString<CH>& str1,
const FString<CH>& str2)

Maybe this is where I picked up the habit.

Thanks for any info,
DSF
"'Later' is the beginning of what's not to be."
D.S. Fiscus

Paavo Helde

unread,
Oct 11, 2014, 3:55:55 PM10/11/14
to
DSF <nota...@address.here> wrote in
news:nnsi3a94gsmhji594...@4ax.com:

> Hello group!
>
> So far, my string template class has been working well. It's based
> on this code to select 8-bit or 16-bit strings:
>
> template <class CH> class FString
> {
> ...
> }
>
> typedef FString<char> FStringA;
> typedef FString<wchar_t> FStringW;

Note that on a lot of platforms wchar_t is 32-bit.

> #ifdef UNICODE
> #define FString FStringW
> #else
> #define FString FStringA
> #endif

This does not respect namespaces and does not follow the rule that macro
names are all-capitals. On top of that, having the macro name the same as
the class name is just confusing as hell. What's wrong with a typedef and
using different names?

As for your questions, the macro substitution is done (at least
conceptually) in the preprocessor stage, before compilation. I.e. all
occurences of FString after the #define are replaced textually with
FStringW or FStringA, before the C++ compiler ever gets to see the code.
I.e. if you have 'FStringA ansistr;' then the C++ compiler will replace
it internally by FString<char>, but this happens in a later compilation
stage where the preprocessing has already been done, so FString is not a
macro any more.

PS. I'm just curious in what way your string class is better than
std::basic_string?

Cheers
Paavo





Charles J. Daniels

unread,
Oct 11, 2014, 8:22:09 PM10/11/14
to
Yes, a string instance should function through its CH nature. Even if it had to access typedefs, etc, you said you explicitly create these as FStringA instances, so if they were to access their internals through lookup (which they don't), they'd still use the right character class.

Charles J. Daniels

unread,
Oct 11, 2014, 8:29:30 PM10/11/14
to
On Saturday, October 11, 2014 12:09:35 PM UTC-7, DSF wrote:
> Hello group!
>
>
>
> So far, my string template class has been working well. It's based
>
> on this code to select 8-bit or 16-bit strings:
>
>
>
> template <class CH> class FString
>
> {
>
> ...
>
> }
>
>
>
> typedef FString<char> FStringA;
>
> typedef FString<wchar_t> FStringW;
>
>
>
> #ifdef UNICODE
>
> #define FString FStringW
>
> #else
>
> #define FString FStringA
>
> #endif
>
>
> When defining a member function outside a template class
>
> declaration, one uses FString<CH>::Function instead of the
>
> non-template FString::Function. I've found myself using the same in
>
> the parameter list:
>
> template <class CH> FString<CH>::FString(const FString<CH>& string);
>
> Or within a member function to construct a new FString:
>
> FString<CH> tfs(p, cs);
>
>
>
> But this works equally well:
>
> template <class CH> FString<CH>::FString(const FString& string);
>
> FString tfs(p, cs);
>
>
>
> Does it matter either way? I do know it's necessary in a construct
>
> like this:
>
> (Within declaration)
>
> friend bool operator==(const FString<CH>& str1, const FString<CH>&
>
> str2);
>
>
>
> (Outside declaration)
>
> template <class CH> inline bool operator==(const FString<CH>& str1,
>
> const FString<CH>& str2)
>
>
>
> Maybe this is where I picked up the habit.
>
>
>
> Thanks for any info,
>
> DSF
>
> "'Later' is the beginning of what's not to be."
>
> D.S. Fiscus

If you include the CH template parameter, I would expect these functions to only accept other FStrings of similar CH foundation, be it unicode/wchar_t or ansi/char. Without an explicit parameter, it may very well accept either type (I'm not 100% certain but fully expect that is correct), and that is not what you want. Test to see if an FStringW will accept FStringA arguments -- you don't want that unless you code with it in mind. My recommendation is to limit the arguments to similar character base by using the CH parameter explicitly to keep them common.

DSF

unread,
Nov 7, 2014, 2:26:08 PM11/7/14
to
On Sat, 11 Oct 2014 14:55:45 -0500, Paavo Helde
<myfir...@osa.pri.ee> wrote:

I just ran across this message. Sorry for the late reply.

>DSF <nota...@address.here> wrote in
>news:nnsi3a94gsmhji594...@4ax.com:
>
>> Hello group!
>>
>> So far, my string template class has been working well. It's based
>> on this code to select 8-bit or 16-bit strings:
>>
>> template <class CH> class FString
>> {
>> ...
>> }
>>
>> typedef FString<char> FStringA;
>> typedef FString<wchar_t> FStringW;
>
>Note that on a lot of platforms wchar_t is 32-bit.

Yes, I know. The FString class makes a lot of calls to functions
that assume wide == 16-bit. But I doubt any of my code will ever see
the light of day beyond my own projects, so portability is not my
chief concern right now.


>
>> #ifdef UNICODE
>> #define FString FStringW
>> #else
>> #define FString FStringA
>> #endif
>
>This does not respect namespaces and does not follow the rule that macro
>names are all-capitals. On top of that, having the macro name the same as
>the class name is just confusing as hell. What's wrong with a typedef and
>using different names?

I know macros bridge across all namespaces. And, more importantly
to me at this time, bridge across all classes. (Come to think of it,
inside a class is a namespace.)

In this case, I believe the very fact that the macro bridges all
boundaries is an asset. After all, the UNICODE definition is most
often used as a program-wide indication of 8-bit or 16-bit characters
in Window$.

Out of curiosity (and future use), how could I write a
namespace-aware version of the above?

To the best of my knowledge, it is not a rule that macros must be
all caps. On my compiler, the function getchar which is listed as a
Standard function, is a macro. None of the functions implemented as
macros are all upper case. I personally use all upper case for macros
that define an immediate value and use mixed case for macros that
simplify a function call.

As to "confusing as hell," actually I thought having the names the
same would be confusing, if it even worked. But it's not. They are
tucked away at the end of FString.h and forgotten about. If I am
writing code dependant on the UNICODE definition, I use FString. If I
need a specific type, such as ANSI (or even UTF-8), I explicitly use
FStringA.

>As for your questions, the macro substitution is done (at least
>conceptually) in the preprocessor stage, before compilation. I.e. all
>occurences of FString after the #define are replaced textually with
>FStringW or FStringA, before the C++ compiler ever gets to see the code.
>I.e. if you have 'FStringA ansistr;' then the C++ compiler will replace
>it internally by FString<char>, but this happens in a later compilation
>stage where the preprocessing has already been done, so FString is not a
>macro any more.
>
>PS. I'm just curious in what way your string class is better than
>std::basic_string?

It's not. But writing it has taught me a lot about templates. I've
also written my own array-type templates for the same reason. Most
books and online articles cover only the most basic elements of
templates, leaving me with the thought "Fine! I Understand. But how do
I do this?" Once I started writing my own, I was able to formulate
better questions and thus, search for better information.

By the way, I've found - at least for me - that studying the STL to
learn to write templates is, to borrow your phrase "confusing as
hell". :o)

>Cheers
>Paavo
>
Thanks for the input,

DSF

unread,
Nov 7, 2014, 2:35:40 PM11/7/14
to
Thank you for the input.

You might want to check the margins in your newsreader. Your reply
showed up as one long line in mine. I had to copy and paste it into
Notepad with Word Wrap on to read it. When I removed the quote
character ">" in this reply, it collapsed to my margins.

Thanks again,
0 new messages