Question

I'm playing around with TMP in GCC 4.3.2's half-implementation of C++11, 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.

Was it helpful?

Solution

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

OTHER TIPS

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.

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

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;

In C++11 there is no way to store temporary string anywhere at compile time. So I can suggest you this approach: (It is fast-made sketch, but it is well descriptive)

#include <stdio.h>

template <char...>
struct StringTuple;

template <char TargHead>
struct StringTuple<TargHead> {
    static constexpr char kSymbol = TargHead;

    static void print() {
        printf(kSymbol ? "%c\n" : "\n", kSymbol);
    }
};

template <char TargHead, char... TargTail>
struct StringTuple<TargHead, TargTail...> {
    using Next = StringTuple<TargTail...>;
    static constexpr char kSymbol = TargHead;

    static void print() {
        if (kSymbol) {
            printf("%c", kSymbol);
            Next::print();
        } else {
            printf("\n");
        }
    }
};

constexpr int length(char *string) {
    return (string[0] == 0) ? 1 : (length(string + 1) + 1);
}

constexpr char get(char *string, int i) {
    return i < length(string) ? string[i] : 0;
}

#define ST(string) \
    StringTuple< \
    get(string, 0), \
    get(string, 1), \
    get(string, 2), \
    get(string, 3), \
    get(string, 4), \
    get(string, 5), \
    get(string, 6), \
    get(string, 7), \
    get(string, 8), \
    get(string, 9), \
    get(string, 10), \
    get(string, 11), \
    get(string, 12), \
    get(string, 13), \
    get(string, 14), \
    get(string, 15), \
    get(string, 16), \
    get(string, 17), \
    get(string, 18), \
    get(string, 19), \
    get(string, 20), \
    get(string, 21), \
    get(string, 22), \
    get(string, 23), \
    get(string, 24), \
    get(string, 25), \
    get(string, 26), \
    get(string, 27), \
    get(string, 28), \
    get(string, 29), \
    get(string, 30), \
    get(string, 31), \
    get(string, 32), \
    get(string, 33), \
    get(string, 34), \
    get(string, 35), \
    get(string, 36), \
    get(string, 37), \
    get(string, 38), \
    get(string, 39), \
    get(string, 40), \
    get(string, 41), \
    get(string, 42) \
    >

int main() {
    ST("Hello, compile-time world!")::print();
}

Bash code to generate a part of macro:

for i in `seq 0 42`; do echo "    get(string, $i), \\"; done

You have to pass large number (1000 or more) to this generator to support all your strings and you have to make static assertion if string exceeds this limit.


I use such generated macros in my own scientific projects. I know it seems messy, but it works. Example of usage of generated macro:

#define PRINT(a) print(a);
FOREACH_MACRO(PRINT, a, b, c) // print(a);print(b);print(c);

I will try find more pretty solution, but at first I will use this.

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.

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

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.

Motti is wrong.

Unfortunately current standard (C++11) not supports variadic template literal operator for string parameters, it is possible only for numbers.

template <char... Args>
operator ""_op();

...

1212_op; // legal, calls operator ""_op<'1','2','1','2'>;
"1212"_op; // illegal

I did not understand purpose of this restriction.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top