Quick question (Theory really). I have a variable that its type alternates depending on a value, for example:
8, 16, 24, 32
And I define this by doing, for example:
uint8_t = 10; // example
But, at the minute I'm switching the "number" and repeating the code but declaring the integer value differently. Which, as you can tell, is a lot of wasteful code and I want to code more effectively.
I'm wondering if It's possible to have template that assigns the variable depending on the value? (If that makes sense)..
if value == 8
uint8_t = foo;
elseif value == 16
uint32_t
...
Any ideas or suggestions? Thank you :)
Like so:
template <unsigned int N> struct IntN;
template <> struct IntN< 8> { typedef uint8_t type; };
template <> struct IntN<16> { typedef uint16_t type; };
template <> struct IntN<32> { typedef uint32_t type; };
template <> struct IntN<64> { typedef uint64_t type; };
IntN<8>::type x = 5;
The template argument has to be a constant expression.
Related
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
Is there a possibility to return a type as a returntype from a function
and use it for a member variable using something like this:
constexpr type myFunction(int a, int b){
if(a + b == 8) return int_8t;
if(a + b == 16) return int_16t;
if(a + b == 32) return int_32t;
return int_64t;
}
template<int x, int y>
class test{
using type = typename myFunction(x, y);
private:
type m_variable;
};
When trying this example in Qt it says
Error: 'constexpr' does not name a type
Error: 'test' is not a template type
class test{
^
In an earlier question someone showed me http://en.cppreference.com/w/cpp/types/conditional this function, but it works only for 2 Types.
You cannot do this with a normal function. However, it is easily done using template meta-programming. This kind of template is sometimes called a type function.
#include <cstdint>
template<int bits> struct integer { /* empty */ };
// Specialize for the bit widths we want.
template<> struct integer<8> { typedef int8_t type; };
template<> struct integer<16> { typedef int16_t type; };
template<> struct integer<32> { typedef int32_t type; };
It can be used like this.
using integer_type = integer<16>::type;
integer_type number = 42;
Remember to precede integer<T>::type with the typename keyword if T is itself a template parameter.
I leave it as an exercise to you to extend this to a template that accepts two integers as parameters and returns the appropriate type based on the sum of the two.
My code base has a huge number of magic integers representing entities in the solution domain. Each has a fixed set of properties which are known at compile time. I'd like to use traits like so:
const int Foo = 1234;
const int Bar = 5678;
// and so on...
template <int N> struct Traits;
template<> struct Traits<Foo>
{
static const int val = 42;
};
template<> struct Traits<Bar>
{
static const int val = 23;
};
// and so on...
I can't find any commentary on the idea in books or the web. What bad things happen if I do this? What is the idiomatic technique which I'm overlooking?
I've got something like this:
template<int SIZE>
struct bin {
private:
public:
struct {
int _value : SIZE;
};
}
Is it possible to change the datatype of _value depending on SIZE? If SIZE is <= 7, I want _value to be a char. If it is >= 8 and <= 15, I want it to be short and if it is <= 31, I want it to be an integer.
This isn't especially elegant, but:
template <unsigned int N>
struct best_integer_type {
typedef best_integer_type<N-1>::type type;
};
template <>
struct best_integer_type<0> {
typedef char type;
};
template <>
struct best_integer_type<8> {
typedef short type;
};
template <>
struct best_integer_type<16> {
typedef int type;
};
template <>
struct best_integer_type<32> {
// leave out "type" entirely, to provoke errors
};
Then in your class:
typename best_integer_type<SIZE>::type _value;
It doesn't deal with negative numbers for SIZE. Neither does your original code, but your text description says to use char if SIZE <= 7. I expect 0 <= SIZE <= 7 will do.
Boost.Integer has utilities for type selection:
boost::int_t<N>::least
The smallest, built-in, signed integral type with at least N bits, including the sign bit. The parameter should be a positive number. A compile-time error results if the parameter is larger than the number of bits in the largest integer type.
boost::int_t<N>::fast
The easiest-to-manipulate, built-in, signed integral type with at least N bits, including the sign bit. The parameter should be a positive number. A compile-time error results if the parameter is larger than the number of bits in the largest integer type.
Atm i have sth like that:
template<int n>
struct Pow
{
enum{val= Pow<n-1>::val<<1};
};
template<>
struct Pow<0>{
enum{val =1};
};
I can acess data like Pow<30>::val. It's good but i want do like this
int main()
{
Pow<30>::val;
and then use variable to
access all of value <0,30>
I knew that i can use array and dynamic programming but can i do that in this way?
Sorry for English.
Using C++0x variadic templates:
template<int... Indices>
struct powers {
static const int value[sizeof...(Indices)];
typedef powers<Indices..., sizeof...(Indices)> next;
};
template<int... Indices>
const int powers<Indices...>::value[sizeof...(Indices)] = { Pow<Indices>::val... };
template<int N>
struct build_powers {
typedef typename build_powers<N - 1>::type::next type;
};
template<>
struct build_powers<1> {
typedef powers<0> type;
};
and then:
int
main()
{
// we want [0..30] inclusive so pass 31 as exclusive upper limit
typedef build_powers<31>::type power_type;
// 0..30 is 31 powers in all
typedef const int array_type[31];
array_type& ref = power_type::value;
// ref[0] .. ref[30] are the values of Pow<0>::val .. Pow<30>::val
}
So that's with using an array but without dynamic initialization. Since you want the result as a variable and not for TMP I feel this is adequate.
When you do Pow<30>::val; you will instantiate the top of your two templates, then when it get's to zero it will instantiate the specialization, and only the final result will be visible at runtime, since templates are resolved at compile time