For the features that you want, ...
- get length at compile time,
- can be included in .h without linker complaining all,
- no multiple copies in .o, in linked output,
... you can use the templated constant idiom, like
template< class Dummy >
struct Foo_
{
static char const s[];
};
template< class Dummy >
char const Foo_<Dummy>::s[] = "Blah blah";
typedef Foo_<void> Foo; // Now you can refer to Foo:s
#include <iostream>
using namespace std;
int main()
{
cout << sizeof( Foo::s ) << " bytes: \"" << Foo::s << "\"\n";
}
You can wrap the generation in a macro.
However, as far as I know the only practical utility is to support char/wchar_t-agnostic code, and for that the pain may be larger than the gain.
EDIT:
MSVC versions 7.1 up through 10.0 incorrectly doesn't accept the sizeof
. The following is a workaround that compiles nicely with g++ 4.4.1, Comeau Online 4.3.10.1, MSVC 7.1 and MSVC 10.0.
#include <stddef.h>
typedef ptrdiff_t Size;
// Substitute a more general countOf
template< Size n >
struct SizedBuf { char sizer[n]; };
template< class Type, Size n >
SizedBuf< n > countOf_( Type (&)[n] ) { return n; }
#define COUNT_OF( array ) sizeof( countOf_( array ).sizer )
#define DEF_STRING( name, value ) \
template< class > \
struct name##_constant_ \
{ \
static char const str[]; \
static Size const length = COUNT_OF( value ) - 1; \
}; \
\
template< class Type > \
char const name##_constant_< Type >::str[] = value; \
\
template< class Type > \
Size const name##_constant_< Type >::length; \
\
typedef name##_constant_<void> name;
DEF_STRING( a, "Argh, MSVC!" )
DEF_STRING( b, "Blah blah" )
DEF_STRING( c, "Currently there's no 'inline' for data in C++." )
#include <iostream>
template< char const* s >
void foo() { std::cout << "foo() says: " << s << std::endl; }
int main()
{
using namespace std;
int const x[a::length] = {}; // Showing off compile time constant.
foo<a::str>(); // Showing off external linkage.
cout << a::length << " characters: \"" << a::str << "\"." << endl;
}
Cheers & hth.,