advice for static template class - c++

I have this problem (histogramming). I've a real space: [a,b] partitioned in some way ([a0=a, a1, a2, ..., b]). The partitioning may be with equal space (a1 - a0 = a2 - a1 = ...) or variables.
I need a class that handle this, with some methods to say given a value in which bin of the partition it belongs; other methods to find the center of a particular bin and more.
During the program I don't like to instantiate a class only to call these simple function like
Binner binner(binning);
binner.get_bin(1.3);
binner.get_centerbin(2);
so I tried to write a static class using template to do something like that:
Binner<binning>::get_bin(1.3);
Binner<binning>::get_centerbin(2);
is it a good idea? There are other way to do it? Now I've free functions like
double get_bin(double bin, Binning binning); // a lot of if/else inside
but I think it's too error prone.
Here my implementation:
enum Binning {CELL, LARGE, BE};
const double binning_LARGE[] = {0, 1.2, 1.425, 1.550, 1.800, 2.5};
const double binning_BE[] = {0, 1.425, 1.550, 2.5};
template<Binning binning>
class Binner
{
public:
static const double* bins;
static const int n;
static int get_bin(double value);
};
template<> const double* myclass<LARGE>::bins = binning_LARGE;
template<> const double* myclass<BE>::bins = binning_BE;
template<> const int myclass<LARGE>::n = sizeof(binning_LARGE) / sizeof(double);
template<> const int myclass<BE>::n = sizeof(binning_BE) / sizeof(double);
template<Binning binning> int myclass<binning>::get_bin(double value)
{
return find_if(bins, bins + n,
bind2nd(greater<double>(), value)) - bins - 1;
}
template<> int myclass<CELL>::get_bin(double value)
{
return static_cast<int>(value / 0.025);
}
is it a good implementation / design?
Is there a way to avoid the n field using std::vector? How?
Is there a way to parametrize the 0.025? I know that double can't be template parameter but can I write something similar to this:
Binner<0.025> binner;
other / advices?
Edit:
For the third point Why I can't do that:
template<Binning binning, int N=100>
class Binner
{
public:
static const double* bins;
static const int n;
static int bin(double value);
};
...
template<Binning binning, int N> int Binner<CELL, N>::bin(double value)
{
return static_cast<int>(value / (2.5 / N));
}

IMHO, your design is ok, if you do not want to instantiate a class. Indeed, it seems a kind of template metaprogramming to me. Whether this makes sense depends on how you are planning to reuse this template.
Using a std::vector would allow you to get rid of the variable to hold the array size, for sure. Now, if this is good for your design, I don't know... it would move some complexity out of your template definition, to the binning definition (which now you can initialize very simply)...
Finally, you can instantiate your template passing a constant to it:
template < Binning binning, unsigned long N, unsigned long M>
class ... {
<using N>
}

have you considered a traits class? Typically if you have static information that you want to separate from the behaviour in a class, you might consider creating a traits class that encapsulates that.
So I'd start with the default behaviour:
enum Binning {CELL, LARGE, BE};
template <Binning binning>
struct BinTraits
{
// default behaviour
int get_bin(double value) { return value / 0.025; }
};
Then I'd provide the specialisations:
const double binning_LARGE[] = {0, 1.2, 1.425, 1.550, 1.800, 2.5};
const double binning_BE[] = {0, 1.425, 1.550, 2.5};
template <typename RandomAccessCollectionT>
int get_bin_impl(double value, RandomAccessCollectionT collection, unsigned size)
{
return find_if(collection, collection + size,
bind2nd(greater<double>(), value)) - collection - 1;
}
template <>
struct BinTraits<LARGE>
{
int get_bin(double value) { return get_bin_impl(value, binning_LARGE, sizeof(binning_LARGE) / sizeof(binning_LARGE[0])); }
};
template <>
struct BinTraits<BE>
{
int get_bin(double value) { return get_bin_impl(value, binning_BE, sizeof(binning_BE) / sizeof(binning_BE[0])); }
};
Then I'd put the actual container behaviour in another class that requires binning behaviour (lets call it HashTable):
template <typename BinTraits>
class HashTable
{
public:
void insert(double value)
{
int bin = BinTraits::get_bin(value);
_bins[bin].insert(value);
}
// _bin is a multimap or something
};

Looking at the usage of find_if and bind2nd as well as functors, it seems as if you are quite knowledgeable about STL and some advanced C++ concepts; yet, what you are trying to do seems to be over-engineering. While I can't fully understand what you are trying to do but it seems that you could do away with templates completely and use just a class (instantiated with different values) and method parameters.

Related

Uses for cpp struct variables passed in templates

I just want to ask if there are any uses for passing variables in cpp as template arguments
template<int a> struct foo {
int x = a;
};
int main() {
foo<2> bar;
std::cout << bar.x;
}
Something like this compiles, works and cout's 2 but the same thing can be done by doing
struct foo {
int x;
foo(int a) : x(a) {}
};
int main() {
foo bar(2);
std::cout << bar.x;
}
So what is the point of using variables in template arguments? I can also see a big flaw in using the first method: the variable a uses memory and isn't destructed after x is changed, as it would be after the constructor is called in the second example. It might be helpful if you showed some reasonable uses for that.
When you pass a variable through a template argument, it can be used in compile time.
For example, if you need to create a statically sized array in your class, you could use the template argument to pass the size of your array:
template <int TSize>
class Foo {
[...] // Do whatever you need to do with mData.
private:
std::array<int, TSize> mData;
};
There are many uses for constants in template parameters.
Static Sizes
This is how you would start implementing something like a std::array.
template <typename T, size_t SIZE>
struct Array {
T data[SIZE];
}
Template parameters are always usable in a constexpr context, so they can be used as sizes for statically sized arrays.
Providing Compile-Time Parameters to Algorithms
Another use is parametrizing algorithms like in the following code sample.
We have a uint32_t in ARGB order but to store it in a file, we might need to reorder it to BGRA or RGBA. We know the order at compile time, so we could use an ArgbOrder template variable.
enum class ArgbOrder { ARGB, RGBA, BGRA };
struct ChannelOffsets {
unsigned a;
unsigned r;
unsigned g;
unsigned b;
};
// and we can get a constexpr lookup table from this enum
constexpr ChannelOffsets byteShiftAmountsOf(ArgbOrder format)
{
...
}
template <ArgbOrder order>
void encodeArgb(uint32_t argb, uint8_t out[4])
{
// We can generate the shift amounts at compile time.
constexpr detail::ChannelOffsets shifts = shiftAmountsOf(order);
out[0] = static_cast<u8>(argb >> shifts.a);
out[1] = static_cast<u8>(argb >> shifts.r);
out[2] = static_cast<u8>(argb >> shifts.g);
out[3] = static_cast<u8>(argb >> shifts.b);
}
void example() {
encodeArgb<ArgbOrder::BGRA>(12345);
}
In this example, we can select the appropriate lookup table at compile time and have zero runtime cost. All that needs to happen at runtime is 4 shifts.
Feature Toggles
We can use bool template variables to toggle features in our code, like for example:
template <bool handleZeroSpecially>
int div(int x, int y) {
if constexpr (handleZeroSpecially) {
return y == 0 ? 0 : x / y;
}
else {
return x / y;
}
}

Declare member function only for specific template instantiation of class

Is it possible to declare a member function only for specific template instantiations of a class? This is why I want to do it:
// Polynomial<N> is a polynomial of degree N
template<int N>
class Polynomial {
public:
//... various shared methods e.g...
double eval(double x) const;
Polynomial<N-1> derivative() const;
Polynomial<N+1> integralFrom(double x0) const;
// ... various shared operators etc.
double zero() const; // only want Polynomial<1> to support this
// only want Polynomial<2> and Polynomial<1> to support the following
// because the solutions rapidly become too difficult to implement
std::vector<double> zeros() const;
std::vector<double> stationaryPoints() const { return derivative().zeros();}
private:
std::array<double,2> coeffs;
}
My current workaround is to just throw an exception from Polynomial<N>::zeros() for N>2 but it would have been nice to detect the problem at compile-time.
You can also use std::enable_if to SFINAE away the zero function.
template< int I >
class Poly {
public:
template<int Ib = I, typename = std::enable_if_t<Ib == 1> >
double zero()
{
return 42;
}
};
int main()
{
Poly< 10 > does_not_compile;
does_not_compile.zero();
//Poly< 1 > compile;
//compile.zero();
}
You can use CRTP to implement zeros and zero in a base class that knows about the derived one.
Then conditionally derive from one that has zeros and/or zero, or not.
template<class P>
struct zeros { /* todo */ };
template<class P>
struct zero:zeros<P> { /* todo */ };
struct nozero {};
template<int N>
struxt Polynomial:
std::conditional_t<
(N==1),
zero<Polynomial<N>>,
std::conditional_t<
(N==2),
zeros<Polynomial<N>>,
nozero
>
>
{
// body
};
Your solution is template specialization, in this case, full specialization.
However, I think you would need to think about your design. Generally, it is not a good idea to define different interfaces for different cases because you are not taking advantage of the abstraction.
For example, think about your stationaPoints() function. This functions should not be available for Polynomial<2> because the derivative is a Polynomial<1> which does not have the zeros() function. Your solution is to add the zeros function to the Polynomial<1> in order to homogenize the interface.
For your case, I guess you would like a solution which includes a N-1 c-vector inside the polynomial type with the zeros and a zero(i) function to get them. Something like this:
template <int N>
class Polynomial {
double _coefs[N+1];
double _zeros[N];
public:
double zero(size_t i) const { assert(i<N); return _zeros[i]; }
// ...
};
In this case, you could decide the strategy to calculate de zeros, depending on your application: constructor?, adding a boolean to know if it has been calculated then it is calculated in the first call to zero, etc...
I guess this solution could be more interesting for you because if you prefer a c-vector to store the coeficients, you wouldn't like the vector based interface of your zeros() function, would you?

templated variable

I currently have the following non templated code:
class Vector{
public:
double data[3];
};
static Vector *myVariable;
void func() {
myVariable->data[0] = 0.;
}
int main() {
myVariable = new Vector();
func();
}
I then want to template the dimension :
template<int DIM> class Vector{
public:
double data[DIM];
};
static Vector<3>* myVariable;
void func() {
myVariable->data[0] = 0.;
}
int main() {
myVariable = new Vector<3>();
func();
}
But I finally want to template my variable as well, with the dimension :
template<int DIM> class Vector{
public:
double data[DIM];
};
template<int DIM> static Vector<DIM> *myVariable;
void func() {
myVariable->data[0] = 0.;
// or perform any other operation on myVariable
}
int main() {
int dim = 3;
if (dim==3)
myVariable = new Vector<3>();
else
myVariable = new Vector<4>();
func();
}
However, this last version of the code produces an error : this static variable cannot be templated ("C2998: Vector *myVariable cannot be a template definition").
How could I possibly correct this error without a complete redesign (like inheriting the templated Vector class from a non templated class, which would require more expensive calls to virtual methods , or manually creating several myVariables of different dimensions) ? Maybe I'm just tired and don't see an obvious answer :s
Edit: Note that this code is a minimal working code to show the error, but my actual implementation templates the dimension for a full computational geometry class, so I cannot just replace Vector by an array. I see that there doesn't seem to be a solution to my problem.
Thanks!
It's been a while, but I've used constants in the template declaration before. I eventually went another direction with what I was working on, so I don't know if it'll ultimately be your solution either. I think the problem here is that any templated variable must know its template argument at compile time.
In your example, Vector<3> and Vector<4> are different types, and cannot be assigned to the same variable. That's why template<int DIM> static Vector<DIM> *myVariable doesn't make any sense; it doesn't have a discernible type.
template<int DIM> static Vector<DIM> *myVariable;
This is not allowed by the language specification. End of the story.
And since I don't understand the purpose of your code, or what you want to achieve, I cannot suggest any better alternative than simply suggesting you to try using std::vector<T>. It's also because I don't know how much am I allowed to redesign your code, and the way you use it, to make your code work.
You can use std::array to template-ize the dimension but you can't cast the pointer of one dimension to the pointer of another.
I think I found!
template<int DIM> class Vector{
public:
double data[DIM];
};
static void *myVariable;
template<int DIM>
void func() {
((Vector<DIM>*)myVariable)->data[0] = 0.;
// or perform any other operation on myVariable
}
int main() {
int dim = 3;
if (dim==3)
{
myVariable = (void*) new Vector<3>();
func<3>();
}
else
{
myVariable = (void*) new Vector<4>();
func<4>();
}
}
Vector<3> and Vector<4> are entirely different types and have no formal relation to one another. The fact that they are superficially similar from your point of view doesn't matter.
If you want them to be equivalent up to a certain type, we have a name for that: interfaces
template <typename Scalar = float>
class BasicVector {
public:
typedef Scalar * iterator;
virtual ~ BasicVector () {}
virtual size_t size () const = 0;
virtual iterator begin () = 0;
virtual iterator end () = 0;
};
template <unsigned N, typename Scalar = float>
class Vector : public BasicVector <Scalar> {
Scalar m_elements [N];
public:
using Scalar :: iterator;
size_t size () const {return N;}
iterator begin () {return m_elements;}
iterator end () {return m_elements + N;}
};
int main () {
BasicVector * a;
a = new Vector <3>;
a = new Vector <4>;
}

How to deduce array size from an enum template argument?

How should I change the code below so that Array<Index> array; is enough and the SIZE is automatically deduced from the enum?
Even if the enum changes, it is guaranteed that it contains SIZE referring to the correct size.
template <typename Enum, int N>
class Array {
public:
int& operator[](Enum index) { return array[index]; }
private:
int array[N];
};
enum Index { X, Y, SIZE };
int main() {
Array<Index, SIZE> array;
array[X] = 1;
return 0;
}
UPDATE: As for "Array<type> means you're creating an array of Type objects" (Jerry) and "the name of class template is a bit misleading" (Nawaz): actually I am creating CustomSqlQueryModel<TableColumns>. The above is just a simplified code, nothing more. Jerry and Nawaz are rigth: this simplified code is unfortunate.
You can write a traits class. This requires a bit of extra work each time you define a new enum type, but no extra work for each occurrence of Array<Index> in user code:
template<class Enum>
struct ArrayTraits;
template<class Enum>
struct Array {
int& operator[](Enum index) { return array[index]; }
private:
int array[ArrayTraits<Enum>::size];
};
enum Index { X, Y, SIZE };
template<>
struct ArrayTraits<Index> {
enum { size = SIZE };
};
int main() {
Array<Index> array;
array[X] = 1;
return 0;
}
One of the advantages of this is you can specialize the traits for external enums you don't control, as long as you know how to get the max size.
As stated, I don't think you can. If, however, you change it to something like:
struct Index {
enum { X, Y, SIZE};
};
Then your template could be something like:
template <class Enum>
class Array {
// ...
private:
int array[Enum::SIZE];
};
...and if the type you pass as Enum doesn't include some positive constant named SIZE,the instantiation won't compile. For the purpose at hand, you'd really kind of prefer that Index was a namespace, but since a namespace isn't a type, I don't think you can use it as a template argument.
I should add, however, that I'm not sure I like this idea at all -- most people are going to think Array<type> means you're creating an array of Type objects, and this is clearly something entirely different from that...
If you want only the size to be template argument, not the type , as from your example it seems that the type of the array would be always int, then why don't you implement this:
template <int size>
class Array {
public:
int& operator[](int index) { return array[index]; }
//Note this addition!
int operator[](int index) const { return array[index]; }
private:
int array[size];
};
int main() {
Array<10> array;
array[0] = 1;
array[1] = 2;
return 0;
}
Note this addition: it's better if you implement const version of operator[] too, so that const Array<> can use it to access the array elements, otherwise your class wouldn't work for const Array<>.

Factory method returning an concrete instantiation of a C++ template class

I have a class
template <unsigned int N>
class StaticVector {
// stuff
};
How can I declare and define in this class a static factory method returning a StaticVector<3> object, sth like
StaticVector<3> create3dVec(double x1, double x2, double x2);
?
"How can I declare and define in this class"
In what class? You've defined a class template, not a class. You can't call a static function of a class template itself, you have to call a particular version of the static function that's part of a real class.
So, do you want the template (and hence all instantiations of it) to have a function returning a StaticVector<3>, or do you want one particular instantiation of that template to have a function returning a StaticVector<3>?
If the former:
template <unsigned int N>
struct SV {
int contents[N];
static SV<3> get3dVec(int x, int y, int z) {
SV<3> v;
v.contents[0] = x;
v.contents[1] = y;
v.contents[2] = z;
return v;
}
};
int main() {
SV<3> v = SV<1>::get3dVec(1,2,3);
}
works for me.
If the latter (you only want get3dVec to be a member of SV<3>, not of all SV<whatever>), then you want template specialisation:
template <unsigned int N>
struct SV {
int contents[N];
};
template<>
struct SV<3> {
int contents[3]; // must be re-declared in the specialization
static SV<3> get3dVec(int x, int y, int z) {
SV<3> v;
v.contents[0] = x;
v.contents[1] = y;
v.contents[2] = z;
return v;
}
};
int main() {
SV<3> v = SV<1>::get3dVec(1,2,3); // compile error
SV<3> v = SV<3>::get3dVec(1,2,3); // OK
}
If for no other reason than to make the calling code look nicer by omitting the basically irrelevant template parameter, I agree with Iraimbilanja that normally a free function (in a namespace if you're writing for re-use) would make more sense for this example.
C++ templates mean that you don't need static functions as much in C++ as you do in Java: if you want a "foo" function that does one thing for class Bar and another thing for class Baz, you can declare it as a function template with a template parameter that can be Bar or Baz (and which may or may not be inferred from function parameters), rather than making it a static function on each class. But if you do want it to be a static function, then you have to call it using a specific class, not just a template name.
Something like :
template< unsigned int SIZE >
StaticVector< SIZE > createVec( const std::tr1::array< double, SIZE >& values )
{
StaticVector< SIZE > vector;
for( int i = 0; i < values.size(); ++i ) // here assuming that StaticVector have [] operator to access values on write
{
vector[i] = values[i];
}
return vector;
}
... or a variant would certainly work. (did'nt test it)
Usage would be:
std::tr1::array< double, 3 > vectorValues = { 10.0, 10.0, 42.0 };
StaticVector<3> vector1 = createVector( vectorValues ); // if the compiler can guess the size from the array information
StaticVector<3> vector2 = createVector<3>( vectorValues ); // if you have to specify the size
An alternative would be to replace std::tr1::array by a basic array but it would be using raw arrays at your own risks :)
First, i believe you originally mean to return
StaticVector<N>
Instead of always a specialization with N==3 . So, what you want to do is writing it like this:
template <unsigned int N>
class StaticVector {
public:
// because of the injected class-name, we can refer to us using
// StaticVector . That is, we don't need to name all template
// parameters like StaticVector<N>.
static StaticVector create3dVec(double x1, double x2, double x2) {
// create a new, empty, StaticVector
return StaticVector();
}
};
If you really want to always return a 3dVector, you would probably want to restrict it to N==3, so that for example StaticVector<4>::create3dVec doesn't work. You can do that using the technique described here.
If you want to have a function like createVec that works with any size, you probably want to replace the parameters with an array. You can do otherwise, but that's advanced and requires some macro tricks applied with boost::preprocessor. It's not worth it i think. The next C++ version will provide variadic templates for this purpose. Anyway,consider using something like this:
I think it would only complicate this unnecessarily here. A quick solution is to use a boost::fusion::vector instead, putting it into the class template instead of the version above:
static StaticVector createVec(double (&values)[N]) {
// create a new, empty, StaticVector, initializing it
// with the given array of N values.
return StaticVector();
}
You could use it with
double values[3] = {1, 2, 3};
StaticVector<3> v = StaticVector<3>::createVec(values);
Note that it accepts an array by reference. You can't give it a pointer. That is because it matches the use of parameters: You couldn't provide less or more arguments for the other way too. It will also protect you from cases like this:
// oops, values is a null pointer!
StaticVector<3> v = StaticVector<3>::createVec(values);
An array never can be a null pointer. Of course if you like, you can always change the array parameter to a pointer. It would just be my personal preference :)
#litb
I wanted to return a 3-element vector. The reason is that these vectors are supposed to be geometric entities, so there is no need for N to be too high (I'm not a string physicist, so I don't work in 11-dimensional spaces). I wanted to create a template to avoid duplicating code but keep 1-, 2- and 3-dimensional vectors as separate types.