Max
Max

Reputation: 101

Building a constexpr template struct (C++11)

I have this code, which works... so far so good :

struct _TYPEIDSTR {};
typedef _TYPEIDSTR *TYPE_ID;
template<class T> _TYPEIDSTR _TYPE_ID;

template<class T> constexpr TYPE_ID getTypeID() { return &_TYPE_ID<T>; }

calling in main like this :

constexpr TYPE_ID id1 = getTypeID<int>();
constexpr TYPE_ID id2 = getTypeID<int>();
RLOG("ID1 : " << id1);
RLOG("ID2 : " << id2);

works perfectly, and I've an unique identifier for each type used in getTypeID() call. Now I want to build a struct that brings some info about a function :

template<typename RES, typename... ARGS> struct _GlobalOverlayInfo {
    bool _member;
    RES(*_fn)(ARGS...);
    size_t _nargs;
    TYPE_ID _argIDs;
    constexpr _GlobalOverlayInfo(RES(*fn)(ARGS...)) :
    _member(false),
    _fn(fn),
    _nargs(sizeof...(ARGS)),
    _argIDs {getTypeID<ARGS>()...}
    {}
};

template<typename RES, typename... ARGS>
constexpr auto getOverlayInfo(RES(*fn)(ARGS...)) {
    return & _GlobalOverlayInfo<RES, ARGS...>(fn); <<---ERROR1
}

using this function :

int pippo(int x) {
    return 0;
}

and calling like this :

constexpr auto x = getOverlayInfo(pippo); <<--- ERROR2

I get the 2 marked errors; ERROR1 is "taking address of a temporary" (but shouldn't it a compile time evaluation ?) and ERROR2 is "error: ‘&’ is not a constant expression". I tried in many ways, but I couldn't success. Where I am wrong ? Is there a way (in C++11) to achieve this result ? All I need is a pointer to an unique structure generated for each RES and ARGS... parameters.

Upvotes: 0

Views: 854

Answers (1)

max66
max66

Reputation: 66230

Not sure to understand what you want to do.

Anyway, if you want to works with C++11 (and avoid C++14 or newer) you can't use a template variable like

template<class T> _TYPEIDSTR _TYPE_ID;

that is a C++14 feature.

If you want a constexpr template identifier, you could use std::type_index, that is available starting from C++11.

If you can't use std::type_index... well, the best I can imagine is a template class with a static variable and a static method that return the pointer to it.

Something like

template <typename>
struct typeId
 {
   static constexpr int const val {};

   static constexpr int const * getId ()
    { return &val; }
 };

template <typename T>
constexpr int const typeId<T>::val;

You can get constexpr values and you can check that are differents

constexpr auto const idInt = typeId<int>::getId();
constexpr auto const idLong = typeId<long>::getId();

std::cout << (idInt != idLong) << std::endl; // print 1

For the function case...

Functions has types and single functions can be template parameters.

So if you want a constexpr identifier for a function, you can create a wrapper as follows

template <typename Ft, Ft f>
struct funcT
 { };

and, using the preceding typeId, get different constexpr values from different functions as follows

int  foo (int) { return 0; }
int  bar (int) { return 0; }
long baz (int, long, long long) { return 0L; }

// ...

constexpr auto idFoo = typeId<funcT<decltype(&foo), &foo>>::getId();
constexpr auto idBar = typeId<funcT<decltype(&bar), &bar>>::getId();
constexpr auto idBaz = typeId<funcT<decltype(&baz), &baz>>::getId();

std::cout << (idFoo != idBar) << std::endl; // print 1
std::cout << (idFoo != idBaz) << std::endl; // print 1

Upvotes: 1

Related Questions