Sign in to follow this  
CJM

Project-wide unique identifiers at compiletime

Recommended Posts

Hey, I'm currently working on a project which requires that at compiletime unique identifiers [ints in particular] can be created. Currently, this forces the users of my project to need to manually use different numbers, but this is not a valid solution. My question is: Is it possible to generate unique numbers which have a project-scope [ie the Visual Studio __COUNT__ macro would be acceptable, but it appears to work only in a single file's scope (perhaps someone knows how to tweak this so that it generates a global count)]. If worst comes to worst, I'm thinking I could make a custom build step which goes through and replaces my own macro (ie __GLOBALCOUNT__, or something less standards-breaking) with everincreasing numbers and then compiles that instead or something - but it's an awful lot of effort for something [which probably wouldn't work] which I would have thought was easier than it's turning out to be. --CJM

Share this post


Link to post
Share on other sites

//UniqueIDGen.h
#ifndef _UNIQUE_ID_GEN_
#define _UNIQUE_ID_GEN_

class CUniqueIDGen
{
//Integer used to generate unique ids
static unsigned int m_iIds;

public:

//constructor and destructor, do nothing
CUniqueIDGen(void) {}
virtual ~CUniqueIDGen(void) {}

/*********************************************
* Function: GetID
*
* Return:
* int: a unique id
*
* Purpose: Function to generate unique class ids
*
*********************************************/

static unsigned int GetID();
};
#endif







//uniqueidgen.cpp
#include "UniqueIDGen.h"
unsigned int CUniqueIDGen::m_iIds = 0;
/*********************************************
* Function: GetID
*
* Return:
* unsigned int: a unique id
*
* Purpose: Function to generate unique class ids
*
*********************************************/

unsigned int CUniqueIDGen::GetID()
{
return CUniqueIDGen::m_iIds++;
}






Call CUniqueIDGen::GetID() when you want a new, unique id.

Share this post


Link to post
Share on other sites
We use perl scripts to modify a .h file during the build. Shell scripts would work just as nice, if your using windows then cygwin is your friend.

with vs.net pre and post build steps can be useful to you in implementing this!

Cheers
Chris

Share this post


Link to post
Share on other sites
What do you need it for?
The addresses of global variables are unique (assigned by the linker), and can safely be converted into an integer by casting it to intptr_t.
It's probably the easiest solution but also fairly limited.

Share this post


Link to post
Share on other sites
if all you need is a guid then use the prebuild stage to call guidgen and copy this guid into a predetermined .h file.

Cheers
Chris

Share this post


Link to post
Share on other sites
Thanks for the replies,

I'm currently writing a small library for use by other programmers working on the same project. Basically put, I've written all of the core parts, and only classes of functions [eg classes with only a void Foo();] need to be written by the other programmers.

What my system currently does [through the (mis)use of template specialisation] is allows them to write arbitrarily identified code - without bothering with any class declarations etc. My system picks them up at runtime and the application can immediately access them. There are other benefits that I won't go into, but the system works perfectly.

For example, the other programmers may write:

FC<1>::Foo()
{
//stuff goes here.
};

and this will immediately become available to the application (and be used by the application) after the next compile. However, if there are two FC classes which have template parameter <1> then the app won't compile.

I basically want to provide a simple way to generate unique IDs for these templates (and so a compiletime option is the only way to go). And there are potentially several hundred of these being written - so a manual solution doesn't really cut it.

Ah well, looks like a prebuild step to replace the __GLOBALCOUNT__ occurrences with a number, and a postbuild step to restore the old files is the way to go...

--CJM

Share this post


Link to post
Share on other sites
The __COUNTER__ counter macro doesn't work? I don't see why it wouldn't, it sounds like that this kind of thing is what it was made for.

Share this post


Link to post
Share on other sites
well maybe typeid can help..

#include <iostream>


template <typename T>
struct id
{
static const int Id;
};

template <typename T>
const int id<T>::Id = reinterpret_cast<int>(typeid(id).name());

struct foo : id<foo>
{};

struct bar : id<bar>
{};

int main(void)
{
std::cout << "foo.Id == " << foo::Id << "\n"
<< "bar.Id == " << bar::Id << "\n";
return 0;
}

Share this post


Link to post
Share on other sites
You don't actually need unigue identifiers across source files. Just always declare the class inside an anonymous namespace.

file1.cpp

namespace {
FC<1>::Foo() {}
}


file2.cpp

namespace {
FC<1>::Foo() {} //No problem!
}


You only need unigue identifiers within a single cpp file. Even if the types look like they would collide, the anonymous namespaces keep the declarations from leaking out.

Share this post


Link to post
Share on other sites
Hey,

Quote:
Original post by Rayno
The __COUNTER__ counter macro doesn't work? I don't see why it wouldn't, it sounds like that this kind of thing is what it was made for.


No, it appears to me that __COUNTER__ works fine within any given source file [ie, the first __COUNTER__ call in each cpp file gets allocated 0, the second 1, and so on, but with the compilation of a new object, it resets to 0]. I suppose that this is probably because only certain parts of the project may need to be recompiled at any given time and to ensure that you get valid global id's for that would be complicated [ie you'd have to store the last allocated id somewhere, like a precompiled header or something].


Quote:
Original post by Deyja
You don't actually need unigue identifiers across source files. Just always declare the class inside an anonymous namespace.


This looks like an alright solution, however I access the attached code through the template itself - like I say FC<3>::GetFC()->Foo(); [and a few other things which are somwhat similar] But perhaps I could rework some of the interfaces and see if I can get it working in some way like this.


Quote:
Original post by DigitalDelusion
well maybe typeid can help..


Certainly looks nice, but doesn't ID get filled at runtime [well in the CRT startup procedure]? Unfortunately, the template parameter needs to be something easily addressable [ie a primitive type like int] rather than a class type for the system to work properly.


Thanks all for your help though, I will look into your solutions.

--CJM

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this