Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Increase compile-time variable with every instantiation of a generic class

I have this class:

template <typename T, uint64_t N>
struct Probe {
  static const uint64_t Counter = N;
  typedef T Type;
};

Which I utilize as:

typedef Probe <int, 0> FirstIntProbe;
typedef Probe <int, 1> SecondIntProbe;
typedef Probe <float, 2> FloatProbe;

Is it possible to create a compile time\macro method which allows me to instantiate this class without specifying the second parameter such as:

typedef Probe <int, Something?> FirstIntProbe;
typedef Probe <int, Something?> SecondIntProbe;
typedef Probe <float, Something?> FloatProbe;

I assume this is isn't possible, but then again I've seen people do things in C++ I wouldn't think was possible before.


Update:

  • It is not necessary to increase by one, it's just important that every probe have it's own number.
  • It is not needed to have unique number across different .cpp files\translation units.
like image 441
Viktor Sehr Avatar asked Jan 28 '13 10:01

Viktor Sehr


2 Answers

You can look into using the __COUNTER__ macro, which is a compiler extension (but supported on GCC and MSVC, among others). Note that __COUNTER__ is unique only per-translation-unit, i.e. per .cpp file.

edit: Header inclusion in multiple translation units is OK. This example links and runs perfectly fine (built on GCC 4.5):

probe.h:

template <typename T, int N>
struct Probe {
    typedef T Type;
};

#define DECLARE_PROBE(type) typedef struct Probe<type, __COUNTER__>

main.cpp:

#include "test.h"

DECLARE_PROBE(int) intprobe;
DECLARE_PROBE(float) floatprobe;

int main(int argc, char** argv) {
    intprobe ip;
    floatprobe fp;
    return 0;
}

test.cpp:

#include "test.h"

DECLARE_PROBE(int) intprobe;
DECLARE_PROBE(float) floatprobe;

static intprobe ip;
static floatprobe fp;
like image 117
sheu Avatar answered Nov 15 '22 02:11

sheu


It's actually very simple if you don't need an integral constant expression (i.e. you're not using Counter as the dimention of an array or such): just use a global static for the counter (or put it in a non-templated base class), and increment it each time you use it in the initialization. Something like:

int currentProbeCounter;

template <typename T>
struct Probe
{
    static int const counter;
    //  ...
};

template <typename T>
const int Probe<T>::counter = ++ currentProbeCounter;

Note that this will only allocate Probe<T>::counter for a given type when (or if) you use it; you might want to use it in the constructors of Probe (even if you don't need to) to ensure its creation. (On the other hand, if you never use it, who cares if it's never created.)

like image 33
James Kanze Avatar answered Nov 15 '22 02:11

James Kanze