On Mon, 09 Dec 2013 00:52:07 -0500, DSF <nota...@address.here>
wrote:
Hello group! A group answer for the group of responders.
Sorry I'm late responding. It's due to a few sick days and the fact
that converting the FStringX classes into a template wasn't as simple
as I thought and I had to go do some more research on templates. The
FStringX classes contained code I'd never tried to put in a template.
Also, I wanted to be sure it actually worked before responding.
First, I'd like to thank Paavo Helde, Robert Wessel and Tobias
M�ller for what turned out to be the best answer. Overload the string
functions.
To my credit, I would like to say I created the code below before
reading Paavo's post on the 10th. I dropped the d and replaced it
with a capital F to visually fit in better with the FString class.
Also, and this will cover Robert Wessel's comment about exporting the
dstr* series to a C program, the dstr* series and other string
manipulators are in a C library I've written. Useable for both
languages. About 80% of the library is written in x86 assembly, so
some kind of wrapper was necessary. (I suppose one could figure out
the name mangling and export C++ names in assembly code, but wrappers
are easier, cost nothing, and are more likely to be portable between
compilers on the same platform.)
This means I couldn't use Paavo's code from the tenth, because it
would break the UNICODE-defined A and W in the string library header.
Come to think of it, I could just #undef dstrlen and any others after
the header is included, then Paavo's method would work. But I think
I'll leave it as it is. It separates the C nomenclature from the C++.
Under the d'oh! category: I don't know if I just forgot it a long
time ago or whatever, but it never occurred to me that non-member
functions could be overloaded, too. It hasn't come up in my
programming. But now...
inline size_t Fstrlen(const char *str){return ::dstrlenA(str);}
inline size_t Fstrlen(const wchar_t *str){return ::dstrlenW(str);}
etc.
... I get the correct version for free! (No overhead!) The compiler
picks the correct FStrlen by parameter type and, with inlining,
Fstrlen(some_string); assembles to a direct call to the proper
dstrlen, A or W.
Problem solved. But to be thorough, answers to other questions.
As to Paavo Helde's question regarding:
// FStr being the template class
typedef FStr<char> FStringA;
typedef FStr<wchar_t> FStringW;
#ifdef UNICODE
#define UCFLAG
#undef UNICODE
#endif
FStringA title;
#ifdef UCFLAG
#undef UCFLAG
#define UNICODE
#endif
Paavo: Sorry, it's probably my fault, but I did not understand your
problem or example. Why is it necessary to undef UNICODE when
declaring an instance of your class? Why cannot you just use some more
typedefs?
And Robert Wessel's similar:
And why does this not work anyway? Assuming your code is actually
using dstrlen (and not dstrlenA or ...W), it should compile as
appropriate based on the whether or not UNICODE is defined.
I am using both Fstring types in the same program, therefore, I
cannot just let the UNICODE definition handle it. The above
preprocessor code was a way to force "A" or "W" while preserving
UNICODE for the rest of the program.
As to Alf P. Steinbach's suggestion regarding std::char_traits, and
Paavo's to study std::basic_string. I've browsed some STL code and I
understand why it's called the ST*!L!*. It's almost a Language unto
itself! Template built upon template built upon....ARRRGH! From what
I've seen myself and read in Web articles about learning templates
from studying the STL: Learning template design by studying the STL
is like learning basic physics by studying NASA shuttle design
documents! :o)
One more:
Paavo said:
OK, so as I understand your string class is just a container for
holding either char or wchar_t type of elements. In that case, what
makes it different from std::basic_string or from MS ATL::CStringT
template classes? Or from std::vector, for that matter? What's the
reason of reimplementing the wheel? If it is for learning, then you
could start with studying the implementation of std::basic_string for
example.
Yes, I know you said "reimplementing," but I've been waiting for
someone to use the phrase for quite a while, so I could write the
paragraph below. This is probably as close as I'm going to get.
To agree with you, reinventing the wheel is a waste of time if you
are building a car, but useful if you are learning to build a wheel.
The term "reinventing the wheel" isn't really valid as a alternate
phrase for wasting one's time. The first wheel was probably a slice
of tree trunk with a hole bored through the center and a branch for an
axle. I imagine those wore out fast. Then somebody probably used
something like animal fat to reduce the friction...etc. The modern
wheel, say on a car, is quite a bit more durable and efficient, thanks
to centuries of reinvention.
Anyway, I did finish the transformation, and after a few basic
tests, I pulled FStringA and W.cpp from a project which parses
hundreds of HTML files and produces a large directory tree of files.
(It's almost ALL string manipulation.) FString.h contains the
template and is already used wherever the FString class would be. I
compiled and ran it, comparing the results to the output of the
FStringA/W version and tweaked the template until they matched.
One question. To save a lot of rewriting, I've typedef'd the
strings as so:
typedef FString<char> FStringA;
typedef FString<wchar_t> FStringW;
I don't see any problem there, but it's followed-up with this to
handle the generic FString UNICODE switching:
#ifdef UNICODE
#define FString FStringW
#else
#define FString FStringA
#endif
I'm concerned about using the same name (FString) in the macro as it
is the template class name. It works, but am I missing any pitfalls?
Thanks!