I was trying to make a bitfield substitute. The primary motive is to have something that can be easily serialized / deserialized. So I created a bitfield class.
template <typename T, size_t ...SIZES>
struct BitField {
using Type = T;
template <size_t I>
void set (T v)
{
...
}
template <size_t I>
T get ()
{
...
}
T value_;
};
So a bitfiled can be created like below:
BitField<uint16_t, 4, 3, 9> field; // creates a 4bit, 3bit and 9bit field in a uint16_t
But there is no nice way to set and get the field. With the above interface, we get and set each field by index.
field.get<0>()
field.set<0>(10)
I wanted to give it a easy syntax, like a variable access and assignment. And I am not clear how I can do it. I created a Field class. The idea is to make a union :
struct Mpls {
using BF = BitField<uint32_t, 20, 3, 1, 8>;
union Label {
BF _bf;
Field<0, BF> _label; // this will act like a variable
Field<1, BF> _exp;
Field<2, BF> _eos;
Field<3, BF> _ttl;
} label;
};
The Field class is defined as below. But I don't know if this is strictly legal?
template <size_t I, typename BF>
struct Field {
using Type = typename BF::Type;
void operator = (Type v)
{
// typecast 'this' to 'BitField class' and here is where I have doubt if this is okay.
((BF *)this)->template set<I>(v);
}
operator Type()
{
return ((BF *)this)->template get<I>();
}
};
I can set the fields like this.
mpls.label._ttl = 0xff;
This works. But is it okay to do this?
Related
This is a question about C++ design: how to avoid introducing a bug as a class changes. The question title indicates my point of view of what I want, but might be the wrong strategy.
I have a class called MyCell that I collect in another class called MyRow. Behind all of this is a database, and the row will, prior to destruction, want to persist itself to the database if any of its cells have changed.
class MyRowUser : public MyRow {
public:
MyRowUser() : MyRow() {}
MyCell<int> registered_user_id;
MyCell<int> birth_year;
MyCell<UserGender> gender;
};
class MyTableUser : public MyTable {
// Contains various things, including a collection
// of MyRowUser objects. Not relevant here, just
// for context.
}
Now this isn't hard: I just have a function called IsDirty() in MyRowUser (or MyRow if I'm clever enough) that loops over the MyCell values and asks each one if it has changed. If any has, then the row persists.
A class of error I'd like to avoid, however, is that I add a new MyCell member to a row and forget to add it to the IsDirty() function that loops over the cells. And here I have not found a clever solution. Every registration scheme I think of so that the row knows about the cells requires actually doing the registrations explicitly. Notably, the MyCell constructors can't know about the Row (about this) in any automatic way I've thought of.
Any design suggestions on how to achieve this more robustly than my current manual iteration?
If you like boiler plate, I got something for you:
#include <tuple>
#include <type_traits>
// This you have to do once:
namespace detail {
template<class... Args>
constexpr void dump(Args...) {}
template<class T, auto en>
struct EnumTypePair {
using type = T;
static constexpr auto value = en;
constexpr EnumTypePair() = default;
constexpr EnumTypePair(const T&) noexcept {}
template<class Tuple>
static constexpr bool fits() {
if constexpr(std::tuple_size_v<Tuple> > value) {
if constexpr(std::is_same_v<typename std::tuple_element_t<static_cast<std::size_t>(value), Tuple>::type, type>) {
return true;
}
}
return false;
}
};
template<class T, auto en>
static constexpr EnumTypePair<T, en> t{};
template<class Cells, typename Cells::names... Ns, class... Ts>
constexpr bool check_cells(EnumTypePair<Ts, Ns> ...pairs) {
using types = typename Cells::types;
using names = typename Cells::names;
static_assert(std::tuple_size_v<types> == static_cast<std::size_t>(names::MAX));
return (pairs.template fits<types>() && ...);
}
}
template<class Row>
struct cells;
template<class T>
struct MyCell {
T content;
auto clean() {};
using type = T;
};
template<class Cells, typename Cells::names name>
using cell_type = typename std::tuple_element_t<static_cast<std::size_t>(name), typename Cells::types>;
template<class Cells, typename Cells::names name>
using content_type = typename cell_type<Cells, name>::type;
template<class ...Ts>
using cell_tuple = std::tuple<MyCell<Ts>...>;
template<class Child>
struct Row {
using names = typename cells<Child>::names;
template<names name>
auto get_cell() -> cell_type<cells<Child>, name>& {
return std::get<static_cast<std::size_t>(name)>(m_cells);
}
template<names name>
auto get() -> content_type<cells<Child>, name>& {
return std::get<static_cast<std::size_t>(name)>(m_cells).content;
}
template<std::size_t ... Ns>
void clean_impl(std::integer_sequence<std::size_t, Ns...>) {
detail::dump( get_cell<names(Ns)>()... );
}
auto make_clean() {
clean_impl(std::make_integer_sequence<std::size_t, names::MAX>{});
}
typename cells<Child>::types m_cells;
};
// This you have to do for each row:
struct MyRow;
template<>
struct cells<MyRow> {
enum names {
id,
birth_year,
gender,
MAX
};
using types = cell_tuple<int, int, char>;
// To check against reordering
static_assert(detail::check_cells<cells<MyRow>>(detail::t<int, id>, detail::t<int, birth_year>, detail::t<char, gender>));
};
struct MyRow: Row<MyRow> {
};
int main() {
MyRow r;
// This is sadly very verbose, maybe you have to write getters for every field.
r.get<cells<MyRow>::id>() = 1;
}
It should be very hard to make an error but you also have to type a lot....
EDIT: By the power of fold expressions, I got rid of a lot of annoying stuff. And now it is impossible to forget the cleaning up. It needs a bit of boilerplate to protect you from reordering the elements and then having a bad day.
EDIT 2: I just saw, that you want to use C++14. This will make the order checking more annoying. The automatic clean up is no problem, I added a workaround for the pack expansion. And I fixed a problem with the integer_sequence.
If you can guarantee that you will never use Cells outside of a common MyRow class and that Cell cannot contain MyRows again, you could do the following:
class MyRow {
public:
static MyRow* g_current_row;
MyRow() : dirty(false) { g_current_row = this; }
void makeDirty() { dirty = true; }
void clearDirty() { dirty = false; }
bool isDirty() const { return dirty; }
private:
bool dirty;
};
and use it in the Cell constructor:
Cell::Cell() : owner(MyRow::g_current_row) {}
void Cell::update(T value) { owner->makeDirty(); }
The MyRowUser constructor will call MyRow::MyRow, which sets g_current_row for the Cell constructors after it.
Sorry for confused title. I don't know how else to say it. Example should explain itself.
I found something called typemaps and use it to my code like this:
template<typename T>
struct typemap
{
static const int INDEX;
};
template<>
const int typemap<Type1>::INDEX = 1;
template<>
const int typemap<Type2>::INDEX = 3;
template<>
const int typemap<Type3>::INDEX = 11;
Type1 Type2 & Type3 are stucts and used like type in here. The INDEX number cannot be inside the struct because there could be another typemap with different numbers but with the same type-object. So the typemap works for different order of the stucts in colection like vector, because the order matter to me.
Next thing is non-template class which has Type1-3 as attributes. And what I'm trying to do is to insert these attributes into vector, that is done with help of std::function. But I need to take general typemap and use it as index to insert to vector.
The only thing i thought it may work is using more templates. Something like the next code, but this is not correct way and since I'm still new to templates I need help to write it correctly so the body of function toVector
start working as i need.
class MyClass
{
Type1 type1_;
Type2 type2_;
Type3 type3_;
..
template<typename T>
void toVector(T& typemap)
{
std::vector<..> vect;
vect.resize(..);
vect[typemap<Type1>::INDEX] = type1_.someFunction(..);
vect[typemap<Type2>::INDEX] = type2_.someFunction(..);
}
};
I'm sure i use the template wrong with the member function, i somehow need to say that T parameter also have some template parameter. Sorry for my english, not native speaker. Also sorry for the ".." It's unrelated to my problem and it would mess the code.
Barry's answer is a better way to do what you are trying to do, but here is the answer to your specific question regarding having a template parameter that is itself a template taking one parameter:
template<template<typename> class type_with_one_template_parameter>
void toVector()
{
std::vector<..> vect;
vect.resize(..);
vect[type_with_one_template_parameter<Type1>::INDEX] = type1_.someFunction(..);
vect[type_with_one_template_parameter<Type2>::INDEX] = type2_.someFunction(..);
}
It wasn't clear why the function had the T& typemap parameter in your original example, so I've removed it.
Instead of adding explicit specializations for INDEX, let's create an actual object type typemap which you can pass around. First some boilerplate:
template <class T>
struct tag_type {
using type = T;
};
template <class T>
constexpr tag_type<T> tag{};
template <int I>
using int_ = std::integral_constant<int, I>;
Now, we create an object with a bunch of overloads for index() which take different tag_types and return different int_s.:
struct typemap {
constexpr int_<3> size() const { return {}; }
constexpr int_<1> index(tag_type<Type1> ) const { return {}; }
constexpr int_<3> index(tag_type<Type2> ) const { return {}; }
constexpr int_<11> index(tag_type<Type3> ) const { return {}; }
};
which is something that you can pass in to a function template and just use:
template<typename T>
??? toVector(T const& typemap)
{
std::vector<..> vect;
vect.resize(typemap.size());
vect[typemap.index(tag<Type1>)] = ...;
vect[typemap.index(tag<Type2>)] = ...;
vect[typemap.index(tag<Type3>)] = ...;
}
How do you insert a transformed integer_sequence (or similar since I am targeting C++11) into a variadic template argument?
For example I have a class that represents a set of bit-wise flags (shown below). It is made using a nested-class because you cannot have two variadic template arguments for the same class. It would be used like typedef Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::WithValues<0x01, 0x02, 0x04> MyFlags. Typically, they will be used with the values that are powers of two (although not always, in some cases certain combinations would be made, for example one could imagine a set of flags like Read=0x1, Write=0x2, and ReadWrite=0x3=0x1|0x2). I would like to provide a way to do typedef Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::WithDefaultValues MyFlags.
template<class _B, template <class,class,_B> class... _Fs>
class Flags
{
public:
template<_B... _Vs>
class WithValues :
public _Fs<_B, Flags<_B,_Fs...>::WithValues<_Vs...>, _Vs>...
{
// ...
};
};
I have tried the following without success (placed inside the Flags class, outside the WithValues class):
private:
struct _F {
// dummy class which can be given to a flag-name template
template <_B _V> inline constexpr
explicit _F(std::integral_constant<_B, _V>) { } };
// we count the flags, but only in a dummy way
static constexpr unsigned _count = sizeof...(_Fs<_B, _F, 1>);
static inline constexpr
_B pow2(unsigned exp, _B base = 2, _B result = 1) {
return exp < 1 ?
result :
pow2(exp/2,
base*base,
(exp % 2) ? result*base : result);
}
template <_B... _Is> struct indices {
using next = indices<_Is..., sizeof...(_Is)>;
using WithPow2Values = WithValues<pow2(_Is)...>;
};
template <unsigned N> struct build_indices {
using type = typename build_indices<N-1>::type::next;
};
template <> struct build_indices<0> {
using type = indices<>;
};
//// Another attempt
//template < _B... _Is> struct indices {
// using WithPow2Values = WithValues<pow2(_Is)...>;
//};
//template <unsigned N, _B... _Is> struct build_indices
// : build_indices<N-1, N-1, _Is...> { };
//template < _B... _Is> struct build_indices<0, _Is...>
// : indices<_Is...> { };
public:
using WithDefaultValues =
typename build_indices<_count>::type::WithPow2Values;
Of course, I would be willing to have any other alternatives to the whole situation (supporting both flag names and values in the same template set, etc).
I have included a "working" example at ideone: http://ideone.com/NYtUrg - by "working" I mean compiles fine without using default values but fails with default values (there is a #define to switch between them).
Thanks!
So I figured it out on my own, I guess I posted too soon.
I was able to get around the error generated with the given code with a dummy template argument in the build_indices and indices template classes above. The argument has to be a typename as they currently have variadic integral types.
(Note: still using the improper _F names here - I have corrected my personal code to not use these reserved name - thanks for the tip)
Here is a working solution which results in the WithValues<...> template to be filled with powers of 2 (1, 2, 4, 8, 16, ...) based on the size of the Flags variadic template.
private:
// dummy class which can be given to a flag-name template
struct _F
{
template <_B _V> inline constexpr
explicit _F(std::integral_constant<_B, _V>) { }
};
// we count the flags, but only in a dummy way
static constexpr unsigned _count = sizeof...(_Fs<_B, _F, 1>);
static inline constexpr
_B pow2(unsigned exp, _B base = 2, _B result = 1)
{
return exp < 1 ?
result :
pow2(exp/2, base*base, (exp % 2) ? result*base : result);
}
template <class dummy, _B... _Is> struct indices
{
using next = indices<dummy, _Is..., sizeof...(_Is)>;
using WithPow2Values = WithValues<pow2(_Is)...>;
};
template <class dummy, unsigned N> struct build_indices
{
using type = typename build_indices<dummy, N-1>::type::next;
};
template <class dummy> struct build_indices<dummy, 0>
{
using type = indices<dummy>;
};
public:
using WithDefaultValues =
typename build_indices<void, _count>::type::WithPow2Values;
I want to store integers for given types which should be used during compilation and during runtime.
Up to now I have the following:
template<typename T>
struct my_int { enum { result = -1 }; };
And I specialize for each type:
template<> struct my_int<a_type> { enum { result = 5 }; };
And I can check during compile time (of course the check here would be against another compile time constant):
static_assert(my_int<a_type>::result == 5, "Bla");
Problem:
This works well, as long as the specialization is in the same namespace. But that is an inconvenience I want to get rid of. So I want to be able to use it in every namespace:
namespace foo {
template<> struct my_int<a_type> { enum { result = 5 }; };
}
namespace bar {
template<> struct my_int<b_type> { enum { result = 7 }; };
}
Any ideas how I could do this?
C++11 and boost is ok for my situation, if really needed.
Update: Seems I gave to little information. The types are mainly enum classes. If you're really interested you can see the real implementation here, http://www.codeduce.com/extra/enum_tools, download the zip and in the header line 33, 34.
For some reason I found the problem description easy to misunderstand, but the linked code makes it clear. In C++11 it's easy:
#define SETUP_ENUM_LENGTH(enum_type, length) \
static constexpr int enum_length(enum_type*) { return length; }
and a
for (int i = 0; i < enum_length((Enum*)0); ++i) {
in the right place. Here's a sample:
#include <iostream>
#include <functional>
#include <boost/preprocessor/variadic/size.hpp>
/**
* Macro to setup an enum completely.
* First parameter is the name, following are the states as plain text.
*/
#define DEF_ENUM(name, ...) \
enum class name : uint8_t { __VA_ARGS__ }; \
SETUP_ENUM_LENGTH(name, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__))
/**
* Once an enum class is defined, this macro makes the size publicly available.
* Needed by enum_array. Already included in DEF_ENUM.
*/
#define SETUP_ENUM_LENGTH(enum_type, length) \
static constexpr int enum_length(enum_type*) { return length; }
/**
* Function to iterate over all elements of an enum.
*/
template<typename Enum>
void enum_for_each(const std::function<void(Enum e)> &fct) {
for (int i = 0; i < enum_length((Enum*)0); ++i) {
fct(static_cast<Enum>(i));
}
}
namespace n {
DEF_ENUM(demo,u,v,w,x,y,z,a,b,c);
}
namespace m {
DEF_ENUM(demo,a=3,b=1,c=4,d=1,e=5);
}
using std::cout;
int main()
{
enum_for_each<n::demo>([](n::demo e) { cout<<int(e); });
cout<<'\n';
enum_for_each<m::demo>([](m::demo e) { cout<<int(e); });
cout<<'\n';
int ndemo[enum_length((n::demo*)0)];
int mdemo[enum_length((m::demo*)0)];
cout << sizeof ndemo << ' ' << sizeof mdemo << '\n';
}
As a side note, that static_cast<Enum>(i) looks troublesome, does it really do the right thing with the m::demo enum?
To preserve the original templated-enum_length usage and so make the array-allocation usage a bit prettier is easy from here, rename the function enum_length_helper and then
template<typename Enum>
struct enum_length {
enum result=enum_length_helper((Enum*)0);
};
If it is possible for your use-case, you could do specialization on a namespace basis and then aggregate as follows, using C++11 since you mentioned it but can work without.
Assume you have a number of namespaces ns_1 to ns_k like this:
namespace ns_i {
template<class T> struct my_int: std::integral_constant<int, -1> {};
/*...*/
enum e_1 { /*...*/ };
template<> struct my_int<e_1>: std::integral_constant<int, 101> {};
/*...*/
enum e_n { /*...*/ };
template<> struct my_int<e_n>: std::integral_constant<int, 142> {};
/*...*/
}
I assume you already have the means to do a unique numbering. Then you aggregate the my_int from all namespaces like this:
namespace your_lib {
template<
class T,
template<class> class sources... /* any number of template classes,
each taking one type argument */
>
struct Union:
std::integral_constant<int, -1> {}; // default -1 for (empty template list)
template<
class T,
template<class> class source, // match first template
template<class> class sources... // match all but first template
>
struct Union<T, source, sources...>:
std::conditional<
source::value == -1,
union<T, sources...>, // recursively call union on all but first tempalte
source // or if there's a value in first, use it
> {};
template<class T> struct my_int :
Union<T, ns_1::my_int, /*...,*/ ns_k::my_int> {};
/* here you could use boost preprocessor to iterate over the namespaces
since you mentionned it */
}
Here's a solution using functions and ADL:
#include <type_traits>
enum TypeInfo
{
Unknown = 0,
TypeA,
TypeB
};
template <TypeInfo x>
using TInfo = std::integral_constant<TypeInfo, x>;
template <class T>
TInfo<Unknown> TypeInfoFunc(T);
template <class T>
struct GetTypeInfo : decltype(TypeInfoFunc(std::declval<T>())){};
namespace a{
class A{};
TInfo<TypeA> TypeInfoFunc(A);
};
namespace b {
class B{};
TInfo<TypeB> TypeInfoFunc(B);
}
int main()
{
static_assert(GetTypeInfo<a::A>::value == TypeA, "");
static_assert(GetTypeInfo<b::B>::value == TypeB, "");
return 0;
}
The TypeInfoFunc is found using ADL meaning that it can be defined in the same namespace as the class your specializing it for.
EDIT
Based on the comments, I think I understand a bit better now. The solution doesn't change much, simply make your function:
namespace a
{
struct A{};//Or whatever class you want to hold data about your type
A TypeInfoFunc(TInfo<TypeA>);
}
and change GetTypeInfo to
template <TypeInfo x>
struct GetTypeInfo : decltype(TypeInfoFunc(TypeInfo<X>())) {};
This way you can call GetTypeInfo<TypeA> and access all the information in (in this case) class A.
you can avoid the need to specialize a structure if you move the type information in the type itself:
template <int V>
struct TypeInfo { enum { result = V, }; };
class yourClass : TypeInfo<2> //works better if you have an enum instad of number
{}
//...
static_assert(a_type::result == 2);
If you do this you will never have the problem with namespaces if the type is declared you will always have access to type info.
I just started playing with metaprogramming and I am working on different tasks just to explore the domain. One of these was to generate a unique integer and map it to type, like below:
int myInt = TypeInt<AClass>::value;
Where value should be a compile time constant, which in turn may be used further in meta programs.
I want to know if this is at all possible, and in that case how. Because although I have learned much about exploring this subject I still have failed to come up with an answer.
(P.S. A yes/no answer is much more gratifying than a c++ solution that doesn't use metaprogramming, as this is the domain that I am exploring)
In principle, this is possible, although the solution probably isn't what you're looking for.
In short, you need to provide an explicit mapping from the types to the integer values, with one entry for each possible type:
template< typename T >
struct type2int
{
// enum { result = 0 }; // do this if you want a fallback value
};
template<> struct type2int<AClass> { enum { result = 1 }; };
template<> struct type2int<BClass> { enum { result = 2 }; };
template<> struct type2int<CClass> { enum { result = 3 }; };
const int i = type2int<T>::result;
If you don't supply the fallback implementation in the base template, this will fail for unknown types if T, otherwise it would return the fallback value.
Depending on your context, there might be other possibilities, too. For example, you could define those numbers within within the types themselves:
class AClass {
public:
enum { inta_val = 1 };
// ...
};
class BClass {
public:
enum { inta_val = 2 };
// ...
};
// ...
template< typename T >
struct type2int
{
enum { result = T::int_val }; // will fail for types without int_val
};
If you give more context, there might be other solutions, too.
Edit:
Actually there isn't any more context to it. I was looking into if it actually was possible, but without assigning the numbers itself.
I think Mike's idea of ordering is a good way to do this (again, for a fixed set of types) without having to explicitly assign numbers: they're implicitly given by the ordering. However, I think that this would be easier by using a type list. The index of any type in the list would be its number. I think something like the following might do:
// basic type list manipulation stuff
template< typename T1, typename T2, typename T3...>
struct type_list;
// meta function, List is assumed to be some instance of type_list
template< typename T, class List >
struct index_of {
enum { result = /* find index of T in List */ };
};
// the list of types you support
typedef type_list<AClass, BClass, CClass> the_type_list;
// your meta function
template< typename T >
struct type2int
{
enum { result = index_of<T, the_type_list>::result };
};
This does what you want. Values are assigned on need. It takes advantage of the way statics in functions are assigned.
inline size_t next_value()
{
static size_t id = 0;
size_t result = id;
++id;
return result;
}
/** Returns a small value which identifies the type.
Multiple calls with the same type return the same value. */
template <typename T>
size_t get_unique_int()
{
static size_t id = next_value();
return id;
}
It's not template metaprogramming on steroids but I count that as a good thing (believe me!)
Similiar to Michael Anderson's approach but this implementation is fully standards compliant and can be performed at compile time. Beginning with C++17 it looks like constexpr values will be allowed to be used as a template parameter for other template meta programming purposes. Also unique_id_type can be compared with ==, !=, >, <, etc. for sorting purposes.
// the type used to uniquely identify a list of template types
typedef void (*unique_id_type)();
// each instantiation of this template has its own static dummy function. The
// address of this function is used to uniquely identify the list of types
template <typename... Arguments>
struct IdGen {
static constexpr inline unique_id_type get_unique_id()
{
return &IdGen::dummy;
}
private:
static void dummy(){};
};
The closest I've come so far is being able to keep a list of types while tracking the distance back to the base (giving a unique value). Note the "position" here will be unique to your type if you track things correctly (see the main for the example)
template <class Prev, class This>
class TypeList
{
public:
enum
{
position = (Prev::position) + 1,
};
};
template <>
class TypeList<void, void>
{
public:
enum
{
position = 0,
};
};
#include <iostream>
int main()
{
typedef TypeList< void, void> base; // base
typedef TypeList< base, double> t2; // position is unique id for double
typedef TypeList< t2, char > t3; // position is unique id for char
std::cout << "T1 Posn: " << base::position << std::endl;
std::cout << "T2 Posn: " << t2::position << std::endl;
std::cout << "T3 Posn: " << t3::position << std::endl;
}
This works, but naturally I'd like to not have to specify a "prev" type somehow. Preferably figuring out a way to track this automatically. Maybe I'll play with it some more to see if it's possible. Definitely an interesting/fun puzzle.
I think it is possible to do it for a fixed set of types, but quite a bit of work. You'll need to define a specialisation for each type, but it should be possible to use compile-time asserts to check for uniqueness. I'll assume a STATIC_ASSERT(const_expr), like the one in Boost.StaticAssert, that causes a compilation failure if the expression is false.
Suppose we have a set of types that we want unique IDs for - just 3 for this example:
class TypeA;
class TypeB;
typedef int TypeC;
We'll want a way to compare types:
template <typename T, typename U> struct SameType
{
const bool value = false;
};
template <typename T> struct SameType<T,T>
{
const bool value = true;
};
Now, we define an ordering of all the types we want to enumerate:
template <typename T> struct Ordering {};
template <> struct Ordering<void>
{
typedef TypeC prev;
typedef TypeA next;
};
template <> struct Ordering<TypeA>
{
typedef void prev;
typedef TypeB next;
};
template <> struct Ordering<TypeB>
{
typedef TypeA prev;
typedef TypeC next;
};
template <> struct Ordering<TypeC>
{
typedef TypeB prev;
typedef void next;
};
Now we can define the unique ID:
template <typename T> struct TypeInt
{
STATIC_ASSERT(SameType<Ordering<T>::prev::next, T>::value);
static int value = TypeInt<T>::prev::value + 1;
};
template <> struct TypeInt<void>
{
static int value = 0;
};
NOTE: I haven't tried compiling any of this. It may need typename adding in a few places, and it may not work at all.
You can't hope to map all possible types to an integer field, because there are an unbounded number of them: pointer types with arbitrary levels of indirection, array types of arbitrary size and rank, function types with arbitrary numbers of arguments, and so on.
I'm not aware of a way to map a compile-time constant integer to a type, but I can give you the next best thing. This example demonstrates a way to generate a unique identifier for a type which - while it is not an integral constant expression - will generally be evaluated at compile time. It's also potentially useful if you need a mapping between a type and a unique non-type template argument.
struct Dummy
{
};
template<typename>
struct TypeDummy
{
static const Dummy value;
};
template<typename T>
const Dummy TypeDummy<T>::value = Dummy();
typedef const Dummy* TypeId;
template<typename T, TypeId p = &TypeDummy<T>::value>
struct TypePtr
{
static const TypeId value;
};
template<typename T, TypeId p>
const TypeId TypePtr<T, p>::value = p;
struct A{};
struct B{};
const TypeId typeA = TypePtr<A>::value;
const TypeId typeB = TypePtr<B>::value;
I developed this as a workaround for performance issues with ordering types using typeid(A) == typeid(B), which a certain compiler fails to evaluate at compile time. It's also useful to be able to store TypeId values for comparison at runtime: e.g. someType == TypePtr<A>::value
This may be doing some "bad things" and probably violates the standard in some subtle ways... but thought I'd share anyway .. maybe some one else can sanitise it into something 100% legal? But it seems to work on my compiler.
The logic is this .. construct a static member function for each type you're interested in and take its address. Then convert that address to an int. The bits that are a bit suspect are : 1) the function ptr to int conversion. and 2) I'm not sure the standard guarantees that the addresses of the static member functions will all correctly merge for uses in different compilation units.
typedef void(*fnptr)(void);
union converter
{
fnptr f;
int i;
};
template<typename T>
struct TypeInt
{
static void dummy() {}
static int value() { converter c; c.f = dummy; return c.i; }
};
int main()
{
std::cout<< TypeInt<int>::value() << std::endl;
std::cout<< TypeInt<unsigned int>::value() << std::endl;
std::cout<< TypeInt< TypeVoidP<int> >::value() << std::endl;
}
I don't think it's possible without assigning the numbers yourself or having a single file know about all the types. And even then you will run into trouble with template classes. Do you have to assign the number for each possible instantiation of the class?
type2int as compile time constant is impossible even in C++11. Maybe some rich guy should promise a reward for the anwser? Until then I'm using the following solution, which is basically equal to Matthew Herrmann's:
class type2intbase {
template <typename T>
friend struct type2int;
static const int next() {
static int id = 0; return id++;
}
};
template <typename T>
struct type2int {
static const int value() {
static const int id = type2intbase::next(); return id;
}
};
Note also
template <typename T>
struct type2ptr {
static const void* const value() {
return typeid(T).name();
}
};