views:

1441

answers:

8

I'm playing around with TMP in GCC 4.3.2's half-implementation of C++0x, and I was wondering if there was a way to somehow do the following:

template <char x, char... c>
struct mystruct {
...
};

int main () {

   mystruct<"asdf">::go();

}

It obviously won't let me do it just like that, and I thought I'd get lucky by using user-defined literals to transform the "asdf" string during compile-time, but GCC 4.3 doesn't support user-defined literals...

Any suggestions? I'd prefer to not do 'a','s','d','f', since this severely hampers my plans for this project.

A: 

I am not sure what you want to achieve, but when you pass "asdf" to the template it's type is char * and the value is the address of the string. Thus a simple approach like the one outlined will fail. It's hard to recommend anything without knowing what problem you are trying to solve in the first place.

lothar
I want to take a literal string, like "asdf" and pass it into a template's parameter list as 'a','s','d','f' would.
Daniel Jennings
A: 

You can't do that. From 14.3.2 in the standard:

A template-argument for a non-type, non-template template-parameter shall be one of:

  • an integral constant-expression of integral or enumeration type; or
  • the name of a non-type template-parameter; or
  • the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to
  • a function or array, or if the corresponding template-parameter is a reference; or
  • a constant expression that evaluates to a null pointer value (4.10); or
  • a constant expression that evaluates to a null member pointer value (4.11); or
  • a pointer to member expressed as described in 5.3.1.
  • [ Note: A string literal (2.13.4) does not satisfy the requirements of any of these categories and thus is not an acceptable template-argument
CTT
It is possible in the proposed C++0x standard, but the only way I've seen so far is with user-defined literals, and I was hoping there was a different way to do it without a compiler that supports user-defined literals.
Daniel Jennings
This is what I mean by with user-defined literals: http://stackoverflow.com/questions/537303/binary-literals/538101#538101
Daniel Jennings
Wow, thanks for that link. I've been wanting something like constexpr for a while.
Dan Olson
A: 

Quote from new standard draft:

14.3.2 Template non-type arguments [temp.arg.nontype]

2 Note: A string literal (2.13.4) does not satisfy the requirements of any of these categories and thus is not an acceptable template-argument.

Example:

template<class T, char* p>
class X 
{ 
X(); 
X(const char* q) { /... / } 
}; 

X<int, "Studebaker"> x1; // error: string literal as template-argument char p[] = "Vivisectionist";
X<int,p> x2; // OK

Try this, but I'm not sure, because http://gcc.gnu.org/gcc-4.3/cxx0x_status.html doesn't say any about this feature.

bb
+3  A: 

I solved a problem similar to this. We needed a different type for each name

template< const char* the_name >
class A
{
    public:
    const char* name( void )
    {
        return the_name;
    }
};

extern const char g_unique_name[]; // defined elsewhere
typedef A<g_unique_name> A_unique;

This will gave you compile time access to the name, and unique instantiation. It however will not let you access the individual characters at run time.

If you want individual character access the only way to achieve it is with a user defined literal. C++0x will be extended to allow the syntax in your main function above but it will still bind the template to a character pointer not to a compile time array of characters.

caspin
+5  A: 

Sadly, you still have to split it into separate characters, eg:

myTemplate<'s','t','r','i','n','g'>

In my humble opinion, this is a huge oversight in the new standard. Some other people agreed, and tried to implement the behavior in GCC with pretty good results. You can find that thread here.

Edit: Some weird problems with the link, so cut and paste from this:

http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/9b0edd169ba2ce3c

Dan Olson
I really appreciate the link to the thread. It covered exactly what I'm wanting to do.
Daniel Jennings
A: 

Try this:

extern const char SOMESTRING[] = "stringhere"; //extern linkage required!

template<const char * const STR>
struct MyStruct
{
  static std::string doThis() { return STR; }
};



MyStruct<SOMESTRING>   testObj; //ok!

Chris

This does not answer the question, the OP wants the string as a variadic template not just a way to use a string as a template parameter.
Motti
A: 

As you say user defined literals will probably solve your problem. Bummer if GCC doesn't support it yet.

My understanding of the C++0x draft is that something like the following will be legal:

template <char... str>
class variadic_string {};

template <char... str>
constexpr variadic_string operator""_var()
{
    return variadic_string<str>();
}

This will let you then use mystruct like this:

mystruct<"asdf"_var>::go();

Where the user defined literal _var transforms "asdf"_var to the variadic <'a', 's', 'd', 'f'> at compile time thanks to the constexpr keyword.

Motti
A: 

A "string" was recently added to Boost.MPL, allowing one to write:

typedef mpl::string<'asdf'> asdf;
typedef mpl::push_back<asdf, mpl::char_<'!'> >::type asdf_bang;

BOOST_ASSERT(0 == std::strcmp(mpl::c_str<asdf_bang>::value, "asdf!"));

Note that the example shown above is a bit contrived, as "strings" made of more than 4 characters have to be split. For example:

typedef mpl::string<'hell','o wo','rld'> hello;
Éric Malenfant