3

I need to do the following:

const char* my_var = "Something";
REGISTER(my_var);
const char* my_var2 = "Selse";
REGISTER(my_var2);
...
concst char* all[] = { OUTPUT_REGISTERED }; // inserts: "my_var1, my_var2, ..."

REGISTER and OUTPUT_REGISTERED are preprocesor macros. This would be great for large number of strings, like ~100. Is it possible to accomplish this?

PS. The code belongs to level-0 "block" – i.e. it is not inside any function. AFAIK, I cannot call regular functions there.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
AllCoder
  • 327
  • 1
  • 2
  • 8
  • 6
    If you were writing C++ code, this would be trivial with a `std::vector`. – Luchian Grigore Aug 23 '12 at 15:52
  • There is no such thing as a "C++ preprocessor," is there? There's a *C* preprocessor supported by most C++ compilers, but you really shouldn't be using it; most of the things it used to do have been turned into checked language features. – ssube Aug 23 '12 at 16:06
  • @peachykeen: There are many things that can only be done with the preprocessor. For example `#define f(x,y) g(#x,x##y,__FILE__,__LINE__)` – Andrew Tomazos Aug 23 '12 at 16:08
  • @AndrewTomazos-Fathomling Absolutely, but this is not one of those, and I was trying not to muddy up the point (that you shouldn't use the preprocessor for this, or a lot of other things). – ssube Aug 23 '12 at 16:10
  • @peachykeen: If you want to build a list like this with something of the form `REGISTER(x);` at global scope - than I think it is only possible with preprocessor. – Andrew Tomazos Aug 23 '12 at 16:14
  • @AndrewTomazos-Fathomling Wouldn't a twist on your answer, using a global function with a static vector (or a pair of functions, yours and a pusher equivalent to your struct) do it? – ssube Aug 23 '12 at 16:15
  • @peachykeen: You can't call a function directly at global scope, only construct global variables with constructors that have side-effects. So without preprocessor best you can do is `REGISTER newvarname(x)` where newvarname has to be unique each time. Using preprocessor you can do this automatically as per my answer below. – Andrew Tomazos Aug 23 '12 at 16:30

1 Answers1

4
#include <iostream>
#include <vector>
using namespace std;

vector<const char*>& all()
{
    static vector<const char*> v;
    return v;
}

struct string_register
{
    string_register(const char* s)
    {
        all().push_back(s);
    }
};

#define REGISTER3(x,y,sr) string_register sr ## y(x)
#define REGISTER2(x,y) REGISTER3(x,y,sr)
#define REGISTER(x) REGISTER2(x, __COUNTER__)

REGISTER("foo");
REGISTER("bar");

int main()
{
}
Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319
  • Why the struct with only a push-on-create? Seems like if you're going to do that, providing a getter or updater would be nice (the question doesn't require them), and if not, you could just make the macro push. What's the advantage of the struct? – ssube Aug 23 '12 at 16:09
  • @peachykeen: You can't execute a function at global scope. This builds the list during static initialization, so on entry to main it is ready. – Andrew Tomazos Aug 23 '12 at 16:10
  • Oh, with the function. Somehow missed that. Makes perfect sense now. :) – ssube Aug 23 '12 at 16:11
  • There is a problem with the _ _COUNTER__. I tried also _ _LINE__, and still "redefinition of sr__LINE__" – AllCoder Aug 23 '12 at 16:29