I have a class that looks similar to this:
class Compound
{
void* pValue0;
void* pValue1;
void* pValue2;
void* pValue3;
void* pValue4;
void* pValue5;
void* pValue6;
void* pValue7;
void* pValue8;
void* pValue9;
void* pValueA;
void* pValueB;
void* pValueC;
};
When I create a new Compound class, I allocate extra memory [sizeof(Compound) + extraSpace]. Each of the pValue's refer to an address in the extra memory.
Now, I would like to reduce the number of pValue's depending on which of them I need. Templates seem like a good fit.
So if I wanted a class Compound<0A>, I would only want pValue0 and pValueA, and then have the compiler remove all other pValues. Essentially, I would want it to then become:
template <uint Mask = 0A>
class Compound<Mask>
{
void* pValue0;
void* pValueA;
}
Is this possible? I got close with enable_if, but when I tried to limit it to a particular mask the compiler threw errors about being unable to find a type when the enable_if case was false.
Thank you all!
This might do:
template<char...>
struct flags_tag {constexpr flags_tag(){}; };
template<char...Cs>
struct make_flags{ using type=flags_tag<Cs...>; };
template<char...Cs>
struct make_flags<'0','x',Cs...>:make_flags<Cs...>{};
template<char...Cs>
struct make_flags<'0','X',Cs...>:make_flags<Cs...>{};
template<char...Cs>
using make_flags_t = typename make_flags<Cs...>::type;
template<char...Cs>
constexpr make_flags_t<Cs...> operator""_flag(){ return {}; }
template<char> struct pValue_t;
template<> struct pValue_t<'0'>{ void* pValue0 = 0; };
template<> struct pValue_t<'1'>{ void* pValue1 = 0; };
// ...
template<> struct pValue_t<'A'>{ void* pValueA = 0; };
template<> struct pValue_t<'B'>{ void* pValueB = 0; };
template<> struct pValue_t<'C'>{ void* pValueC = 0; };
template<class flags>
struct Compound;
template<char...Cs>
struct Compound< flags_tag<Cs...> >:
pValue_t<Cs>...
{};
Then you use it like:
using my_type = Compound< decltype( 0x0A_flag ) >;
int main() {
my_type test;
std::cout << test.pValue0 << test.pValueA << '\n';
}
which seems to do what you want.
I'd also disable the copy/move ctor of your Compound type, and make its other constructors private with a friend factory function.
Note that this code can generate an exponential number of classes (2^12, or 4k), and that can cause binary bloat (if any per-class code isn't inlined out of existence).
[live example]
std::conditional is similar to std::enable_if, except conditional always returns a type.
std::conditional<satisfies(Mask), void*, EmptyClass> would be the way to swap the member's types out conditionally and have it compile.
The problem is, C++ does not allow empty members. The size will be 1. To solve this problem, you'd need the empty member optimization. This will achieve the memory layout that you're asking for, but unfortunately, this will make the class members difficult to read. You can add accessor functions to mitigate this, if you think it's worth pursuing.
I am assuming that the Compound class shall contain pointers to objects of different classes and not void pointers, as you said in your comment.
I don't know if that is a good idea because I think there is something wrong in the design, but you could use tuples and template specializations on ints to select the type you want:
class Class0;
class ClassA;
template<int> struct Compound {};
template<> struct Compound<0A>
{
typedef std::tuple<Class0*, ClassA*> type;
}
// other mapping from mask to type
typename Compound<0A>::type aCompund(ptr0, ptrA);
Related
As I understand, typedef cannot be used for overloading but what if I need to use some different types as arguments to the function pointer?
How can I make it work with the following functionality?
{
public:
typedef void (*InitFunc)(float x);
typedef void (*InitFunc)(int a, char b); //Needs to be added
virtual void initialize(InitFunc init) = 0;
};
Edit:
I cannot use C++17, so can't use variant
As commented, the easiest way is a union, although not very type safe and C++-y. Here is an example with inheritance, since you commented that you want inheritance.
typedef void (*FloatInit)(float x);
typedef void (*IntCharInit)(int a, char b);
union InitFn {
FloatInit fi;
IntCharInit ici;
};
struct Foo {
void initialize(InitFn) = 0;
};
struct FloatFoo: public Foo {
void initialize(InitFn f) override {
f.fi(42.0f);
}
};
void test(float) {}
// ...
auto x = FloatFoo{};
x.initialize(InitFn{test});
As mentioned by other commenters, you can use std::variant to enhance type safety and get rid of the manual union definition:
typedef void (*FloatInit)(float x);
typedef void (*IntCharInit)(int a, char b);
typedef std::variant<FloatInit, IntCharInit> InitFn;
struct Foo {
void initialize(InitFn) = 0;
};
struct FloatFoo: public Foo {
void initialize(InitFn f) override {
std::get<FloatInit>(f)(42.0f);
}
};
void test(float) {}
// ...
auto x = FloatFoo{};
x.initialize(InitFn{test});
One solution is to create a simple wrapper class template instead, to allow the compiler to automatically generate instantiations as necessary. This is relatively simple if init is always guaranteed to be a non-member function (and by extension, an actual function and not a functor/lambda).
// Quick-and-dirty transparent callable wrapper, to serve as overloadable "type alias".
template<typename>
class InitFunc;
template<typename Ret, typename... Params>
class InitFunc<Ret(*)(Params...)> {
public:
// Supply component types if needed.
// Tuple used for params, for convenience.
using return_type = Ret;
using param_types = std::tuple<Params...>;
using func_type = Ret(Params...);
using func_ptr_type = func_type*;
using func_ref_type = func_type&;
// Create from pointer or reference.
constexpr InitFunc(func_ptr_type p = nullptr) : ptr(p) {}
constexpr InitFunc(func_ref_type r) : ptr(&r) {}
// Transparent invocation.
// Deduces argument types instead of relying on Params, to allow for perfect forwarding.
template<typename... Ts>
constexpr return_type operator()(Ts&&... ts) { return ptr(std::forward<Ts>(ts)...); }
// Convert back to original type if necessary.
operator func_ptr_type() { return ptr; }
operator func_ref_type() { return *ptr; }
private:
// Actual function pointer.
func_ptr_type ptr;
};
// And a nice, clean creator, which can be renamed as necessary.
template<typename Init>
constexpr auto make(Init func) { return InitFunc<Init>(func); }
This creates a nice little wrapper that can easily be optimised out entirely, and will compile as long as C++14 support is available.
Note that you require a C++11 compiler (or variadic templates, rvalue references, perfect forwarding, and constexpr support) at the absolute minimum, and will need to modify make() to have a trailing return type for pre-C++14 compilers. I believe this is compatible with C++11 constexpr, but I'm not 100% sure.
If you want InitFunc to be able to accept pointers/references-to-member-function (including functors and lambdas), you'll need to provide an additional version to isolate it into a non-member "function", and likely bind it to a class instance. It may be worth looking into std::bind() in this case, although I'm not sure if it has any overhead.
In this case, I would suggest splitting the member types off into a base class, to reduce the amount of code you'll need to duplicate.
// Quick-and-dirty transparent callable wrapper, to serve as overloadable "type alias".
template<typename>
class InitFunc;
// Supply component types if needed.
// Tuple used for params, for convenience.
// Using actual function type as a base, similar to std::function.
template<typename Ret, typename... Params>
class InitFunc<Ret(Params...)> {
public:
using return_type = Ret;
using param_types = std::tuple<Params...>;
using func_type = Ret(Params...);
using func_ptr_type = func_type*;
using func_ref_type = func_type&;
};
// Non-member functions.
// As member types are now dependent types, we qualify them and use `typename`.
// Yes, it looks just as silly as you think it does.
template<typename Ret, typename... Params>
class InitFunc<Ret(*)(Params...)> : public InitFunc<Ret(Params...)> {
// Actual function pointer.
typename InitFunc::func_ptr_type ptr;
public:
// Create from pointer or reference.
constexpr InitFunc(typename InitFunc::func_ptr_type p = nullptr) : ptr(p) {}
constexpr InitFunc(typename InitFunc::func_ref_type r) : ptr(&r) {}
// Transparent invocation.
// Deduces argument types instead of relying on Params, to allow for perfect forwarding.
template<typename... Ts>
constexpr typename InitFunc::return_type operator()(Ts&&... ts) { return ptr(std::forward<Ts>(ts)...); }
// Convert back to original type if necessary.
operator typename InitFunc::func_ptr_type() { return ptr; }
operator typename InitFunc::func_ref_type() { return *ptr; }
};
// See ecatmur's http://stackoverflow.com/a/13359520/5386374 for how to accomodate member functions.
// ...
// Non-member function make() is unaffected.
// An overload will likely be needed for member functions.
template<typename Init>
auto make(Init func) { return InitFunc<Init>(func); }
Despite the awkwardness inside our derived specialisation, any code that relies on InitFunc shouldn't (to my knowledge) see any changes to its API; the previous example will work just fine if we swap to this new InitFunc, and be none the wiser after recompilation.
Note that it will change the ABI, though, and thus any code compiled for the simpler InitFunc will need to be recompiled for this version.
I am using C++ (not 11) and using some libraries which have different typedefs for integer data types. Is there any way I can assert that two typedefs are the same type? I've come up with the following solution myself.. is it safe?
Thanks
template<typename T>
struct TypeTest
{
static void Compare(const TypeTest& other) {}
};
typedef unsigned long long UINT64;
typedef unsigned long long UINT_64;
typedef unsigned int UINT_32;
int main()
{
TypeTest<UINT64>::Compare(TypeTest<UINT64>()); // pass
TypeTest<UINT64>::Compare(TypeTest<UINT_64>()); // pass
TypeTest<UINT64>::Compare(TypeTest<UINT_32>()); // fail
}
In C++11, you could use std::is_same<T,U>::value.
Since you don't have C++11, you could implement this functionality yourself as:
template<typename T, typename U>
struct is_same
{
static const bool value = false;
};
template<typename T>
struct is_same<T,T> //specialization
{
static const bool value = true;
};
Done!
Likewise you can implement static_assert1 as:
template<bool> struct static_assert;
template<> struct static_assert<true> {}; //specialization
Now you can use them as:
static_assert<is_same<UINT64,UINT64>::value>(); //pass
static_assert<is_same<UINT64,UINT32>::value>(); //fail
Or you could wrap this in a macro as:
#define STATIC_ASSERT(x) { static_assert<x> static_assert_failed; (void) static_assert_failed; }
then use as:
STATIC_ASSERT(is_same<UINT64,UINT64>::value); //pass
STATIC_ASSERT(is_same<UINT64,UINT32>::value); //pass
If you use macro, then you would see the following string in the compiler generated message if the assert fails:
static_assert_failed
which is helpful. With the other information in the error message, you would be able to figure out why it failed.
Hope that helps.
1. Note that in C++11, static_assert is an operator (which operates at compile-time), not a class template. In the above code, static_assert is a class template.
Since you don't have C++11, use boost.
BOOST_STATIC_ASSERT(boost::is_same<T, U>::value);
You can write some kind of your assert function, instead of BOOST_STATIC_ASSERT.
std::type_info might help you.
I'm experimenting a little with type traits and template specialization. For example:
enum TestEnum
{
VALUE0 = 0,
VALUE1 = 1,
VALUE2 = 2
//... And so on...
};
template<int Value>
class cTestClass;
//specializations
template<>
class cTestClass<VALUE0>
{
static int GetVal() { return VALUE0; }
};
template<>
class cTestClass<VALUE1>
{
static int GetVal() { return VALUE1; }
};
template<>
class cTestClass<VALUE2>
{
static int GetVal() { return VALUE2; }
};
typedef cTestClass<VALUE0> cClassVal0; //(1)
typedef cTestClass<VALUE1> cClassVal1; //(2)
typedef cTestClass<VALUE2> cClassVal2; //(3)
//Later in the code
template<int Value>
cTestClass<Value>* Create()
{
return new cTestClass<Value>(/*..*/);
}
//And using the upper function
cClassVal2* pTestClass = Create<VALUE2>();
This works absolutely fine. The goal is to provide a way for users of an interface not to deal with templates and template parameters (Ok, besides using Create()). That is the reason for the typedefs at the bottom of the code.
No here is what I want to achieve next:
cTestClass should have one member variable which is accessible via member functions. Under certain circumstances I either want the user being able to modify the member variable or not to modify the member variable. So basically this means two member functions, one that returns the member as const reference (not modifyable) or non const (modifyable). Problem is, if both those member functions are provided, the user always has the chance to modify the member variable. So I want to choose the appropriate member function during compile time and just provide one correct member function for the user.
The only solution I came up with looks basically like this:
template<int Value, bool ConstAccess>
class cTestClass;
//specializations
template<>
class cTestClass<VALUE0, true>
{
const std::string& get() const
{
return m_strName;
}
static int GetVal() { return VALUE0; }
private:
std::string m_strName;
};
template<>
class cTestClass<VALUE0, false>
{
std::string& get()
{
return m_strName;
}
static int GetVal() { return VALUE0; }
private:
std::string m_strName;
};
//For every upcoming cTestClass two specializations
typedef cTestClass<VALUE0, true> cConstObjectVal0;
typedef cTestClass<VALUE0, false> cObjectVal0;
//And for the rest...
Besides the fact that this really seams to be unnecessary code duplication I always have to specify two typedefs for every possible VALUE. But the user should not be confronted with that choice, he should always be able to just use the types as given above (see 1, 2, 3).
Is this even possible?
I googled a bit and came up with the following site: ACCU:: An introduction to C++ traits.
This explanation seems to a matching blueprint, but I really can't put the pieces together.
Another possibility I found is described here: C++ Template specialization to provide extra member function? Just adding one function would be possible, but this still doesn't solve my typedef problem.
We can try to employ SFINAE:
typedef char True;
typedef long False;
template <typename VALUE0, typename IsConst>
class cTestClass
{
public:
template <typename T, T> struct TypeCheck {};
const std::string& get(TypeCheck<IsConst, True >* dummy = NULL);
std::string& get(TypeCheck<IsConst, False>* dummy = NULL);
}
typedef cTestClass<VALUE0, True> cConstObjectVal0;
typedef cTestClass<VALUE0, False> cObjectVal0;
I didn't try to compile it yet, but the general principle is to prevent one of the functions to compile properly, then, due to the SFINAE principle, the compiler will just throw away the wrong version.
I have a class parameterised by some template parameters:
template<typename Scalar, typename Integrator, int Dimension>
class foo;
Each of the template parameters can be one of a few possible types. Currently the type of foo used is hard-coded in man typedef foo<...> foo_type. I wish to adapt my program so that a collection of foo's are supported; something like:
if (desired_foo_str == "2DSimpleFloat")
{
foo<float,Simple,2>(params).method();
}
else if (desired_foo_str == "3DSimpleDouble")
{
foo<double,Simple,3>(params).method();
}
else
{
std::cout << "Unsupported foo."
}
The interface of foo does not depend on its template parameters. My question is how can I improve this solution? I know boost::mpl provides a type vector but it seems more for compile time reductions as opposed to run-time switching.
Clarification
Lets say (this is a simplification) that my program takes a set of points in N-dimensions (provided by the user) and integrates them. Certain combinations of dimensions, integration methods and scalar types can be accelerated by SIMD (hence the use of template parameters). All combinations of foo<A,B,N> are valid however different users (all of whom will have compiled my program) will require only a couple of specific specializations for their work. I wish to allow for:
$ integrate --method=2DSimpleFloat mypoints2d.dat
$ integrate --methid=3DSimpleDouble mypoints3d.dat
so run-time selection of what method they wish to use. I am wondering what kind of frame-work best allows me to associate types with strings such that I can better handle the above scenario.
You could make templated default method which throws an error, and template-specializations per combination that you support.
class Simple {};
template<typename Scalar, typename Integrator, int Dimension>
class foo
{
public:
void method();
foo() {}
};
// default implementation throws an error
template<typename Scalar, typename Integrator, int Dimension>
void foo<Scalar,Integrator,Dimension>::method() { cout << "unsupported\n"; };
// override default for supported cases:-
template<>
void foo<double,Simple,2>::method() { cout <<"method1\n"; };
template<>
void foo<double,Simple,3>::method() { cout <<"method2\n"; };
// test program
void main() {
foo<float,Simple,2> a; a.method(); // output "unsupported"
foo<double,Simple,2> b; b.method(); // output "method1"
foo<double,Simple,3> c; c.method(); // output "method2"
}
You should be able to mix general purpose implementations and special purpose overides freely throughout the class; (e.g. perhaps some permeation can be handled with SIMD intrinsics or whatever)
If all the class methods were identical and generic, a convenient way to restrict use might be to restrict the constructor so that undesired cases can't be instantiated
in general if the mechanisms of overloading and templates are being used correctly, you should be able to avoid checking types manually where they're used.
This can all work compile time statically linked without any pointers or virtual dispatch.
If the supported implementations are to be the same, the over-rides can be wrappers to direct to another templated method as suggested above.
Your question doesn't provide enough information for a complete answer, but I have a hunch: Perhaps you should look into refactoring your code so as to separate the part that is independent of the parameters from the code that depends on the template parameters.
The typical example is taken from Scott Meyers's book. Suppose you have a square matrix multiplicator, and you write this as a full template:
template <typename T, unsigned int N>
Matrix<T, N> multiply(Matrix<T, N>, Matrix<T, N>)
{
// heavy code
}
With this setup, the compiler would generate a separate piece of code for each size value N! That's potentially a lot of code, and all that N provides is a bound in a loop.
So the suggestion here is to turn compile-time into runtime parameters and refactor the workload into a separate function, and only use template stubs to dispatch the call:
template <typename T>
void multiply_impl(unsigned int N,
MatrixBuf<T> const & in1, MatrixBuf<T> const & in1,
MatrixBuf<T> & out)
{
// heavy work
}
template <typename T, unsigned int N>
Matrix<T, N> multiply(Matrix<T, N> const & in1, Matrix<T, N> const & in1)
{
Matrix<T, N> out;
multiply_impl(N, in1.buf(), in2.buf(), out.buf());
}
You could do something similar: Put all the argument-independent code in a base class, and make the derived classes templates. The runtime can then use a factory function to create the correct concrete instance at runtime. As an alternative to inheritance you can also make a type-erasing wrapper class that contains a private pointer-to-base, and the runtime populates this with concrete derived implementation instances.
I'm guesing you are looking for register pattern. This is only my draft, so don't rely on it.
class AbstractFooFactory
{
virtual AbstractFoo* create( ParamsType cons& params ) = 0;
// or construct on stack and call .method()
virtual void createAndCallMethod( ParamsType cons& params ) = 0;
};
class FooRegister
{
~FooRegister(); // delete all pointers
template< typename FooFactory >
void operator() ( FooFactory const & factory ) // for boost::mpl:for_each
{ map[factory.getName()]= new FooFactory( factory ); }
AbstractFooFactory* get( std::string name );
std::map< std::string , AbstractFooFactory* > map;
};
template< typename Scalar, typename Integrator, typename Dimension >
class FooFactory: public AbstractFooFactory
{
typedef FooFactory<Scalar, Integrator, Dimension > type; // Metafunction
std::string getName(); // this will be a bit hard to implement
AbstractFoo* create( ParamsType cons& params );
void createAndCallMethod( ParamsType cons& params );
};
Simple trails may be used for storing type names:
template< typename Type >
struct NameTrails
{
static const char const* value;
};
template<> const char const* NameTrails<int>::value = "Int";
template<> const char const* NameTrails<float>::value = "Float";
template<> const char const* NameTrails<double>::value = "Double";
template<> const char const* NameTrails<Simple>::value = "Simple";
template<> const char const* NameTrails<Complex>::value = "Complex";
template< typename Scalar, typename Integrator, typename Dimension >
std::string FooFactory::getName()
{
return boost::lexical_cast<std::string>( Dimension::value ) + "D"
+ NameTrails< Integrator >::value
+ NameTrails< Scalar >::value;
}
And now you need to register all types using mpl::for_each:
FooRegister fooRegister;
typedef boost::mpl::vector<Simple,Complex> IntegratorsList;
typedef boost::mpl::vector<int,float,double> ScalarsList;
typedef boost::mpl::range_c<int,1,4> DimensionsList;
typedef boost::mpl::vector<
boost::mpl::vector< Simple, float, boost::mpl::int_<2> >,
boost::mpl::vector< Simple, double, boost::mpl::int_<3> >,
... other types or full cross join ... > FooList;
boost::mpl::for_each< FooList, boost::mpl::quote3<FooFactory> >(
boost::ref(fooRegister) );
What i don't know is how to cross join IntegratorsList, ScalarList, range_c<int,1,4> to constuct full FooList.
fooRegister.get("2DSimpleFloat")->createAndCallMethod(params);
You probably want to do this statically, so yes it is possible, but i find it rather difficult to achieve better performance then a simple dynamic map or hash map.
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();
}
};