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?
> 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
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" );
}
================================================================================
// 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)
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.