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

A

Alf P. Steinbach

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

Ioannis Vranos

Alf said:
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";
}
 
A

Alf P. Steinbach

* Ioannis Vranos:
* Alf P. Steinbach:
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";
}

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" );
}
================================================================================
 
P

Pete Becker

Alf said:
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.
 
A

Alf P. Steinbach

* Pete Becker:
// 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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top