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

Cheap (simple, efficient) solution for literal strings in templates?

1 view
Skip to first unread message

Alf P. Steinbach

unread,
Mar 24, 2005, 2:13:57 AM3/24/05
to
Depending on a template type argument Char I'd like a literal string,
and for that matter also literal char constants, to be 'char' or 'wchar_t'
base type, i.e.

template< typename Char >
bool isPassword( std::basic_string<Char> const& s )
{
return s == "password"; // Cheap solution for Char === wchar_t?
}

The cheapest solution I could make to work involved a class + macro
like

struct literal_string
{
wchar_t const* myWide;
char const* myNarrow;

literal_string( wchar_t const* w, char const* n )
: myWide( w ), myNarrow( n )
{}

operator wchar_t const* () const { return myWide; }
operator char const* () const { return myNarrow; }
};

#define S( a ) literal_string( a, L ## a )

I couldn't make that work with the strings as template arguments.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Ioannis Vranos

unread,
Mar 24, 2005, 2:27:37 AM3/24/05
to
Alf P. Steinbach wrote:

> Depending on a template type argument Char I'd like a literal string,
> and for that matter also literal char constants, to be 'char' or 'wchar_t'
> base type, i.e.
>
> template< typename Char >
> bool isPassword( std::basic_string<Char> const& s )
> {
> return s == "password"; // Cheap solution for Char === wchar_t?
> }
>
> The cheapest solution I could make to work involved a class + macro
> like
>
> struct literal_string
> {
> wchar_t const* myWide;
> char const* myNarrow;
>
> literal_string( wchar_t const* w, char const* n )
> : myWide( w ), myNarrow( n )
> {}
>
> operator wchar_t const* () const { return myWide; }
> operator char const* () const { return myNarrow; }
> };
>
> #define S( a ) literal_string( a, L ## a )
>
> I couldn't make that work with the strings as template arguments.


I did not understood what exactly you want to do, however you can
"store" string literals like this:


#include <vector>

int main()
{
using namespace std;

vector<char *> charLiterals;

charLiterals.push_back("literal1");
charLiterals.push_back("whatever");

vector<wchar_t *> wcharLiterals;

wcharLiterals.push_back(L"literal1");
wcharLiterals.push_back(L"whatever");


char *charlits[5]= {"lit1", "lit2" };

charlits[3]= "whatever";

wchar_t *wcharlits[5];

wcharlits[0]= L"wide character literal";
}

--
Ioannis Vranos

http://www23.brinkster.com/noicys

Alf P. Steinbach

unread,
Mar 24, 2005, 7:24:49 AM3/24/05
to
* Ioannis Vranos:
> * Alf P. Steinbach:

Well, best of all I'd like the ability to just write a string directly
where it's used, and that's what the solution I sketched above provided:
if the context requires 'char', then it's 'char', and ditto for 'wchar_t'.

For efficiency, however, and also for the ability to use as template
arguments and other compile-time stuff, it would be nice to declare the
strings at namespace scope, even in a header file.

Here's what I came up with for that; it's ugly, isn't it? :-)

================================================================================
struct dummy_type {};

template< template<typename Char> class LiteralStringDefiner >
struct cameleon_string_
{
operator char const* () { return LiteralStringDefiner<char>::s; }
operator wchar_t const* () { return LiteralStringDefiner<wchar_t>::s; }
};

#define DEFINE_CAMEL( name, literal_string ) \
namespace literal \
{ \
template< typename Dummy> struct name ## _char { static char const s[]; }; \
template< typename Dummy> char const name ## _char<Dummy>::s[] = "s"; \
\
template< typename Dummy> struct name ## _wchar_t { static wchar_t const s[]; };\
template< typename Dummy> wchar_t const name ## _wchar_t<Dummy>::s[] = L"s"; \
\
template< typename Char> struct name ## _; \
\
template<> struct name ## _<char>: name ## _char<dummy_type> {}; \
template<> struct name ## _<wchar_t>: name ## _wchar_t<dummy_type> {}; \
\
typedef cameleon_string_<name ## _> name; \
}

DEFINE_CAMEL( huh, "duh" )
================================================================================


With that I can write code like


================================================================================
template< typename Char >
void display( Char const* )
{
}

template< typename Char >
bool is_password( std::basic_string<Char> const& s )
{
display<Char>( literal::huh() );
return s == literal::huh_<Char>::s;
}

int main()
{
is_password<char>( "birthdate" );
is_password<wchar_t>( L"spouse" );
}
================================================================================

Pete Becker

unread,
Mar 24, 2005, 8:49:09 AM3/24/05
to
Alf P. Steinbach wrote:
> Depending on a template type argument Char I'd like a literal string,
> and for that matter also literal char constants, to be 'char' or 'wchar_t'
> base type, i.e.
>
> template< typename Char >
> bool isPassword( std::basic_string<Char> const& s )
> {
> return s == "password"; // Cheap solution for Char === wchar_t?
> }
>

// the usual double indirection:
#define CONCATX(a, b) a ## b
#define CONCAT(a, b) CONCATX(a, b)

// define two password strings
#define PASSWORD "password"
#define WIDE_PASSWORD CONCAT(L, PASSWORD)

// look, ma, no templates!
bool isPassword(const std::basic_string<char>& s)
{
return s == PASSWORD;
}

bool isPassword(const std::basic_string<wchar_t>& s)
{
return s == WIDE_PASSWORD;
}

Or, if you really want a template function (which probably won't work
right for any type other than char or wchar_t), make the first one a
template. But that seems like overkill.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

Alf P. Steinbach

unread,
Mar 24, 2005, 9:18:52 AM3/24/05
to
* Pete Becker:

> Alf P. Steinbach wrote:
> > Depending on a template type argument Char I'd like a literal string,
> > and for that matter also literal char constants, to be 'char' or 'wchar_t'
> > base type, i.e.
> >
> > template< typename Char >
> > bool isPassword( std::basic_string<Char> const& s )
> > {
> > return s == "password"; // Cheap solution for Char === wchar_t?
> > }
> >
>
> // the usual double indirection:
> #define CONCATX(a, b) a ## b
> #define CONCAT(a, b) CONCATX(a, b)
>
> // define two password strings
> #define PASSWORD "password"
> #define WIDE_PASSWORD CONCAT(L, PASSWORD)
>
> // look, ma, no templates!

Well, there are macros instead, but that can easily be fixed by using
'const' (that's a newfangled language feature that some extreme ivory-tower
theoricians claim is preferable to macros).

But whether macro or 'const' those values won't have external linkage.

So the other solution I posted, in reply to Ioannis Vranos, used templates
to obtain external linkage for values defined in a header file.


> bool isPassword(const std::basic_string<char>& s)
> {
> return s == PASSWORD;
> }
>
> bool isPassword(const std::basic_string<wchar_t>& s)
> {
> return s == WIDE_PASSWORD;
> }
>
> Or, if you really want a template function (which probably won't work
> right for any type other than char or wchar_t), make the first one a
> template. But that seems like overkill.

The actual code doesn't have anything to do with passwords or indeed
freestanding functions; part of it goes like this:

template< typename Char >
class environment_: public process_arguments_<Char>
{
public:
// Helper class for parsing variable defs, and passing them around
// as arguments.
class variable
{
string_t my_name;
string_t my_value;

bool invariant() const;
// return name().length() > 0 &&
// name().find( LTS( "=" ) ) == string_t::npos;
^^^^^^^^^^

There are many more such instances and ideally I'd like it all in the header
file.

But then this is just something I'm doing because I sort of stumbled into it.

0 new messages