10

Is it possible to have a macro to have:

CHAR_LIST(chicken)

to expand to:

'c', 'h', 'i', 'c', 'k', 'e', 'n'

[Reason I want it: because for even moderate-sized strings, a macro is hugely more convenient than manually expanding. And the reason I need to expand is passing in a string to a varidiac template]

Heptic
  • 3,076
  • 4
  • 30
  • 51
  • 8
    And you need a variadic template here because..... –  May 31 '11 at 17:04
  • Have you tried creating some kind of macro in your text editor to do this for you? – Benjamin Lindley May 31 '11 at 18:03
  • I'm currently working on a solution, but why exactly do you need to pass this to a variadic template? This might be important. – Xeo May 31 '11 at 23:40
  • @Xeo, I'm trying to do string-switching at compile time -- and the case statements are like case_statement<'c', 'h', 'i', 'c', 'k', 'e', 'n'>(...functor if this case is true...) – Heptic Jun 01 '11 at 07:45
  • @Heptic: Is it okay if you only have an array that you can iterate? :) – Xeo Jun 01 '11 at 09:50
  • @Xeo: No, not really :(. I'm doing some TMP, so just need a macro to make it look a little nicer. :D – Heptic Jun 01 '11 at 10:52
  • @Heptic: I meant an array as a **template argument** to your function. :) Imagine `['a','b','c','d']` to be the array, you'd get `case_statement<['a','b','c','d']>(...)`. – Xeo Jun 01 '11 at 10:54
  • This would also be useful for [hiding strings](https://stackoverflow.com/questions/1356896/how-to-hide-a-string-in-binary-code) – mikeLundquist Feb 18 '22 at 12:52

2 Answers2

9

Update by the answerer, July 2015: Due to the comments above on the question itself, we can see the the real question was not about macros per se. The real problem the questioner wanted to solve was to be able to pass a literal string to a template that accepts a series of chars as non-type template arguments. Here is an ideone demo of a solution to that problem. The implementation there requires C++14, but it's easy to convert it to C++11.

------------

I think we need a clearer example of how this macro is to be used. We need an example of the variadic template. (Another Update: This won't work doesn't work for me on g++ 4.3.3 in a variadic template even when c++0x support is turned on, but I think it might be interesting anyway.)

#include<iostream> // http://stackoverflow.com/questions/6190963/c-macro-to-convert-a-string-to-list-of-characters
#include "stdio.h"

using namespace std;

#define TO_STRING(x) #x
#define CHAR_LIST_7(x)   TO_STRING(x)[0] \
                       , TO_STRING(x)[1] \
                       , TO_STRING(x)[2] \
                       , TO_STRING(x)[3] \
                       , TO_STRING(x)[4] \
                       , TO_STRING(x)[5] \
                       , TO_STRING(x)[6] \

int main() {
        cout << TO_STRING(chicken) << endl;
        printf("%c%c%c%c%c%c%c", CHAR_LIST_7(chicken));
}

The line defining d is what you're interested in. I've included other examples to show how it's built up. I'm curious about @GMan's link to automate the counting process.

Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
  • 3
    Very interesting, if this can be extended to automatically count the string length it would seem to be the solution :) /me goes to try – Heptic May 31 '11 at 17:32
  • This macro can be used as an array initialiser, but not in a variadic template. – Blagovest Buyukliev May 31 '11 at 17:39
  • Actually it does work in variadic templates. Example: http://hpaste.org/47313/exand – Heptic May 31 '11 at 18:33
  • @Heptic, I keep getting `error: an array reference cannot appear in a constant-expression` errors. What compiler you using? I'm on g++ (Ubuntu 4.3.3-5ubuntu4) 4.3.3 with --std=gnu++0x – Aaron McDaid May 31 '11 at 23:01
2

Nope, sorry, can't be done. There is no operation to split a string into characters. The closest you could get is through recursive metaprogramming, but that will give you the array as an object, not the actual text representation.

Blindy
  • 65,249
  • 10
  • 91
  • 131
  • +1: The other alternative is an independent code-generation step in your build process. – Oliver Charlesworth May 31 '11 at 17:11
  • That would be best if it was *really* needed, and somehow I don't think having `'c', 'h', 'i', 'c', 'k', 'e', 'n'` in the code is worth the trouble :) – Blindy May 31 '11 at 17:15
  • 1
    There is an operation to split into chars. See my (klunky) answer. -1 for undue pessimism - I hope this appears reasonable. – Aaron McDaid May 31 '11 at 17:35
  • @Aaron, maybe you didn't see a comment to an answer that was deleted where Heptic explained that these characters were meant to be template parameters. Your answer doesn't work in that case, making this answer the more correct one. Not deserving of a -1. – Mark Ransom May 31 '11 at 17:53
  • I'm undoing my downvote. I still think the answer should explain why, rather than just saying "Nope, sorry, can't be done". I've seen this a few times on SO, without basis. I'd never noticed Blindy on SO before. I think I'll trust @Blindy in future :-) – Aaron McDaid May 31 '11 at 18:05
  • The solution below actually does work on template parameters, so it seems like there's a solution. Now the problem is just automatic length counting – Heptic May 31 '11 at 18:35
  • That's exactly the part you can't do, you can't get how many characters there are in a string at compile time as text (not to be confused with the metaprogramming `sizeof` approach). – Blindy May 31 '11 at 18:43
  • Wouldn't the `char` just after the end be '\0'? Maybe this can be used to terminate the template, with a specialization. If that worked, then you could just pass in TO_STRING(x)[0] all the way to TO_STRING(x)[100] without difficulty. I'd try it myself, but even the basic example from @Heptic doesn't compile for me. – Aaron McDaid May 31 '11 at 23:05