I am trying to create a type safe abstraction for registers. Shortly explained a register can contain a field of bits which have some special meaning and the bits in question can usually be either set to a range of valid values (specified by an enum) or to any integer value (if so specified). The fields in a single register are described by an enum.
What I am having some trouble with is how do I create a template that allows me to specify the valid combinations that this enum VALUE can only be paired with a) value specified by an enum b) any integer value. The actual set function is the same for any combination (it will cast down to underlying value from the enum class values). Other thing to note is that I'd like the set() method to be generic in a way that it is in a separate file from the actual register definitions so adding static_asserts() there etc. to prevent some type combinations etc. is not a good solution. I have a solution that is very close to what I want but I'm not sure how can I get the template type deduction to work so that I don't need to type the name of the enum type twice per call.
enum class Definitions : uint32_t
{
kBit0 = 1UL << 0,
kBit1 = 1UL << 1,
kField0 = 0xF0,
kField1 = 0xF00,
kField2 = 0xF000
};
enum class Field0Values
{
Setting1 = 0x01,
Setting2 = 0x02,
};
enum class Field1Values
{
Setting1 = 0x01,
Setting2 = 0x02,
};
template<class MaskType, MaskType value> struct allowed_type;
template<> struct allowed_type<Definitions, Definitions::kField0> {
using type = Field0Values;
};
template<> struct allowed_type<Definitions, Definitions::kField1> {
using type = Field1Values;
};
template<> struct allowed_type<Definitions, Definitions::kField2> {
using type = uint32_t;
};
template<class MaskType, MaskType maskValue>
constexpr void set(typename allowed_type<MaskType, maskValue>::type value) {}
int main()
{
// Valid set operations
set<Definitions, Definitions::kField0>(Field0Values::Setting1);
set<Definitions, Definitions::kField1>(Field1Values::Setting1);
set<Definitions, Definitions::kField2>(42);
// Mistakes, will not compile
set<Definitions, Definitions::kField0>(Field1Values::Setting1);
set<Definitions, Definitions::kField1>(Field0Values::Setting1);
set<Definitions, Definitions::kField1>(7);
}
This is nearly what I want except I would like to be able to just say set<Definitions::kField0>(Field0Values::Setting1). I CAN do that if I declare a template specialization like:
template<Definitions mask>
constexpr void set(typename allowed_type<Definitions, mask>::type value);
But the issue with that is that I do not want to provide the implementation for that specialization, I just want it to use the base template function, not sure how can I do that. How can I get the template type deduction to deduce the type without having to create the template specialization?
Also interested if someone has another approach that doesn't have this type deduction issue.
How about setting the template argument to auto in both allowed_type and set?
template<auto value> struct allowed_type;
template<> struct allowed_type<Definitions::kField0> {
using type = Field0Values;
};
template<auto maskValue>
constexpr void set(typename allowed_type<maskValue>::type) {}
Alternatively, if you prefer to keep allowed_type as is, you can also only change set:
template<auto maskValue>
constexpr void set(typename allowed_type<decltype(maskValue), maskValue>::type value) {}
Related
In Python, you can return a class instead of its instance from a function, because a class is just an instance of a 'metaclass' called type.
Can you do the same in C++? Say I want a function to return a class, so that the calling code can then take the returned class and call a static method on it without ever creating an instance of it. Possible ?
You can't return a type; but you can return an identity object for a type. Then you can process it similarly to the given type. For example:
#include <iostream>
// in C++20, this is available as std::type_identity<>
template<typename T>
struct ID {};
template<typename T>
struct ToType;
template<typename T>
struct ToType<ID<T>>
{ using type = T; };
template<typename T>
using totype_t = typename ToType<T>::type;
struct MyType
{
static fn() { std::cout << "ok" << std::endl; }
};
auto GetMyType()
{
return ID<MyType>();
}
int main()
{
auto proc = [](auto x) {
totype_t<decltype(x)>::fn();
};
proc(GetMyType());
}
Note that, a function's return type must still be a given type, so you can't return this way based on runtime parameters. (You can, of course, use compile-time arguments for that.)
However, in C++ you also have type aliases. That's basically a way to write 'function-like' (mathematically: mapping) type expressions to define your type calculation. E.g.,
template<size_t I>
using MyType = std::conditional_t<(I < 50), char, int>; // if (I < 50) then char else int
A useful trick here is to use decltype(expression) for expression's evaluation type.
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?
I am writing a source file library with a series of declarations and macros that are related in a one-to-one relationship. The first is a list of categories, as an enumeration:
typedef enum {
CID_SYS, // Highest-priority devices. Reserved.
CID_CTRL, // Controlling unit, only one per segment
CID_SENSOR, // Data providers (temperature, speed, clock)
CID_BROADCAST, // Broadcast messages (system messages extension)
...
} category_id_t;
I'm using this enumeration to define 16-bit message identifiers with the category bits as the most significant 3 bits. Those identifiers are segmented in two variable-size bit blocks in the less significant bits. One of these blocks depends on the above category. So I've also defined a list of sizes as macros, one per category like this:
#define SYS_MESSAGES_MAX 256
#define CTRL_MESSAGES_MAX 64
#define SENSOR_MESSAGES_MAX 8
#define BROADCAST_MESSAGES_MAX 64
...
It's then easy to mask out the category and retrieve the relevant bits, i.e. the function ID, which lies in the least significant bits of the message ID. With CID_SYS for instance:
unsigned short function_id = message_id & (SYS_MESSAGES_MAX-1)
I need a class template with the category as an argument. The number of messages in the category, which is implied by the latter should somehow be deduced by the template class at compile-time without resorting to arrays. The class template might look like something similar:
template <category_id_t CAT>
class Manager
{
...
unsigned message_count() const { return /* a number depending on CAT */ }
};
With -Os the compiler resolves as much as it can at compile-time without adding code or variables when it can. So I'd like to make the most of it. My current attempt is using a function template and specialization:
template<category_id_t CAT>
unsigned cat_size();
template<category_id_t CAT>
class Manager
{
public:
unsigned size() const { return cat_size<CAT>(); }
};
template<> unsigned cat_size<CID_SYS>() { return SYS_MESSAGES_MAX; }
template<> unsigned cat_size<CID_CTRL>() { return CTRL_MESSAGES_MAX; }
The above example would then be:
unsigned short function_id = message_id & (size()-1) /* This should be a constant resolved at compile-time */
The generic template function is intentionally left without its definition to have a linker error generated in the case I forget a specialization when I add a category. However I find this inelegant and convoluted.
How could I make this more elegant?
I definitely don't want to pass the message count as a template argument because I still need the C-style macros: my library is supposed to be used by C and C++ applications.
This is actually doable without templates now that we have constexpr. The cat_size mapping can be done using a constexpr function with a switch. You could define *_MESSAGES_MAX as separate constexpr ints if you don't like have the values in the return like the below
constexpr int cat_size(category_id_t cat) {
switch (cat) {
case CID_SYS:
return 256; // SYS_MESSAGES_MAX
case CID_CTRL:
return 64; // CTRL_MESSAGES_MAX
case CID_SENSOR:
return 8; // SENSOR_MESSAGES_MAX
case CID_BROADCAST:
return 64; // BROADCAST_MESSAGES_MAX
}
}
Calculating the function id is just another constexpr that calls through to the switch. I've replaced unsigned short with std::uint16_t to make sure you get what you want, note this requires you to #include <cstdint>
constexpr std::uint16_t function_id(category_id_t cat, std::uint16_t msg) {
return msg & (cat_size(cat)-1);
}
Looking at the generated assembly for the following, we can see that it is actually calculated at compile time
int main() {
constexpr std::uint16_t msg{0xCDEF};
constexpr auto fid = function_id(CID_SYS, msg);
std::cout << fid << '\n';
}
This may not be neat or elegant but I had some search meta-function to find a type in a type-list as follows:
#include <type_traits>
template<typename ...Ts>
struct TypeList; //Represent a list of types to be queried
struct Nil; //empty type, a placeholder type if we cannot find what we need
//Searches given 'Item' in types ('Ts...') where equality check is done by 'Equals'
template<typename Item, template<class,class> class Equals, typename ...Ts>
struct Find;
//Specializes the 'Find' with 'TypeList' provides syntactic sugar
template<typename Item, template<class,class> class Equals, typename ...Ts>
struct Find<Item, Equals, TypeList<Ts...>> : Find<Item, Equals, Ts...>
{};
//recursive 'Find' metafunction. If 'T' is equal to 'Item' then return 'T'
// Else recurse to the rest of the type list
template<typename Item, template<class,class> class Equals, typename T, typename ...Ts>
struct Find<Item, Equals, T, Ts...> {
using type = typename std::conditional<
Equals<Item, T>::value, //Evaluate T
T, //if predicate returns true than T is the type we are looking for
Find<Item, Equals, Ts...> //else recurse into the list
>::type;
};
//specialization for one type 'T', that is the last element of the original type-list
template<typename Item, template<class,class> class Equals, typename T>
struct Find<Item, Equals, T> {
using type = typename std::conditional<
Equals<Item, T>::value, //Evaluate T
T, //if predicate returns true than T is the type we are looking for
Nil //else return Nil for meaningful compile messages
>::type;
};
You can have this in a utility header and use it for various purposes. Boost has two different libraries for such classes (meta-programming) one of them is MPL and the other modern version is Hana. You may want to check one of those libraries.
With such type-searching mechanism we can define a type for your category and hold category related information.
//A special structure to define your compile-time attributes for each category
template<category_id_t CatId, int CatMask>
struct Category
{
static const category_id_t id = CatId;
static const int mask = CatMask;
};
//define a set of categories with their attributes (ie. id and mask)
using Categories = TypeList<
Category<CID_SYS, SYS_MESSAGES_MAX-1>,
Category<CID_CTRL, CTRL_MESSAGES_MAX-1>,
Category<CID_SENSOR, SENSOR_MESSAGES_MAX-1>,
Category<CID_BROADCAST, BROADCAST_MESSAGES_MAX-1>
>;
Then we define a predicate and a specialized search function to find related category with given id as follows:
//
template<typename Item, typename Category_>
using CategoryEquals = std::integral_constant<
bool,
Item::value == Category_::id
>;
template<category_id_t CatId>
using FindCategory = Find<
std::integral_constant<category_id_t, CatId>, //Item
CategoryEquals, //Equals
Categories
>;
Finally, we can find and use categories like this:
template<category_id_t CatId>
unsigned short GetFunctionId(unsigned short messageId)
{
using FoundCat = typename FindCategory<CatId>::type; //search for category
return messageId & FoundCat::mask;
}
Sample usage:
int main()
{
unsigned short msg = 259;
unsigned short functionId = GetFunctionId<CID_SYS>(msg);
std::cout << functionId; //prints 3
}
Ok suppose I have a struct like so:
struct Example{
uint8_t var0;
uint32_t var1;
uint16_t var2;
};
And suppose I have an instance (note constexpr) of the class that looks like this:
constexpr Example exp = {10,11,12};
And I want to somehow get the bit representation of this into a template parameter pack.
An example of what this would look like:
typedef SomeTemplate<
/* first variable: 1 byte */ 10,
/* second variable: 4 bytes */ 11, 0, 0, 0,
/* third variable: 2 bytes */ 12, 0> mydef;
My knee jerk response to doing this is to do some template meta programming magic with some unions, but unfortunately this is not possible because accessing a union in the way I want is undefined behavior at compile time (ie error).
My ultimate goal with all of this is to put an instance of a user defined type into as a template parameter....something like this:
template<Example exp>
class OtherClass{
};
So the reason I am on this rabbit trail is I could take class Example and give a templated constructor which would take a list of uint8_ts in and then initialize itself that way (thus still constexpr and effectively allowing me to pass it in directly).
So is there any way to convert an arbitrary struct instance into an bit pattern at compile time (and all constexpr)?
Here is what I eventually ended up doing:
template<class T,class... Args_t>
struct Statifier{
constexpr T operator()() { return T(Args_t()...); }
constexpr operator T() { return T(Args_t()...); }
};
And then you use it like so:
template<class T, T value>
using ic = integral_constant<T,value>;
struct Point{
int x;
int y;
int z;
constexpr Point(int x,int y,int z) : x(x),y(y),z(z) { }
};
typedef Statifier<Point,ic<int,12>,ic<int,12>,ic<int,12> > triple;
triple is now a type and can be passed into a template parameter.
Limits of this approach:
You can only use types which can be differentiated by their constructors
You have to use types that have constexpr constructors
It can be cumbersome to initialize
But it is still awesome.
Thanks for you comments....they did help me find this method
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();
}
};