Boost logo

Boost :

From: Eric Niebler (eric_at_[hidden])
Date: 2008-03-21 14:33:10


Eric Niebler wrote:
> Matt Hurd wrote:
>> The main problem is you can't do this without a pre-processing stage
>> elegantly. There is just no way to support a macro or any other
>> succinct form of compile time string without a pre-processing stage.
>> It is just clumsy.
>
> Here's a slightly goofy way to do it using multi-character character
> constants. I'm pretty sure this is non-portable, but it works with gcc
> and msvc.

<snip>

> // Accept a string as a template parameter!
> template<char const *sz>
> struct greeting
> {
> void say_hello() const { std::cout << sz << std::endl; }
> };
>
> int main()
> {
> greeting<ctstring<'Hell','o wo','rld!'>::value> g;
> g.say_hello();
> }

Now that I think about it some more, there's really nothing stopping us
from taking this much farther -- access individual characters, calculate
the length, slice and substr, even search and replace. There's no reason
why ctstring<> can't implement most of the std::string interface at
compile time.

Here's a slightly cleaned up version, in case anybody wants to carry
this forward. A good first step might be to make this a valid Fusion
sequence.

#include <iostream>
#include <boost/mpl/integral_c.hpp>
#include <boost/preprocessor/arithmetic/div.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>

#define MAX_CTSTRING_LENGTH 128
#define MAX_CTSTRING_PARAMS BOOST_PP_DIV(MAX_CTSTRING_LENGTH, 4)

#define CTLENGTH(c) ((c>0xffffff)+(c>0xffff)+(c>0xff)+1)
#define CTAT(c,i) (char)((c)>>(8*(CTLENGTH(c)-(i)-1)))

template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(MAX_CTSTRING_PARAMS,
unsigned int C, 0)>
struct ctstring
{
     static std::size_t const size
       = CTLENGTH(C0)
       + ctstring<BOOST_PP_ENUM_SHIFTED_PARAMS(MAX_CTSTRING_PARAMS,
C)>::size;

     template<unsigned int I, bool B = (I < CTLENGTH(C0))>
     struct at
       : boost::mpl::integral_c<char, CTAT(C0,I)>
     {};

     template<unsigned int I>
     struct at<I, false>
       : ctstring<BOOST_PP_ENUM_SHIFTED_PARAMS(MAX_CTSTRING_PARAMS, C)>
             ::template at<I-CTLENGTH(C0)>
     {};

     static char const c_str[];
};

template<BOOST_PP_ENUM_PARAMS(MAX_CTSTRING_PARAMS, unsigned int C)>
char const ctstring<BOOST_PP_ENUM_PARAMS(MAX_CTSTRING_PARAMS, C)>::c_str[] =
{
#define M0(z, n, data) at<n>::value
     BOOST_PP_ENUM(MAX_CTSTRING_LENGTH, M0, ~)
#undef M0
};

template<>
struct ctstring<>
{
     static std::size_t const size = 0;

     template<unsigned int>
     struct at
       : boost::mpl::integral_c<char, '\0'>
     {};

     static char const c_str[];
};

char const ctstring<>::c_str[] = {'\0'};

// Accept a string as a template parameter!
template<char const *sz>
struct greeting
{
     void say_hello() const { std::cout << sz << std::endl; }
};

int main()
{
     std::cout << ctstring<'Hell','o wo','rld!'>::size << std::endl;

     greeting<ctstring<'Hell','o wo','rld!'>::c_str> g;
     g.say_hello();

     std::cout << ctstring<>::c_str << std::endl;

     return 0;
}

-- 
Eric Niebler
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk