I'd like to write an n-dimensional histogram class. It should be in the form of bins that contains other bins etc. where each bin contains min and max range, and a pointer to the next dimension bins
a bin is defined like
template<typename T>
class Bin {
float minRange, maxRange;
vector<Bin<either Bin or ObjectType>> bins;
}
This definition is recursive. So in run time the user defines the dimension of the histogram
so if its just 1-dimension, then
Bin<Obj>
while 3-dimensions
Bin<Bin<Bin<Obj>>>
Is this possible?
Regards
Certainly, C++11 has variable length parameter lists for templates. Even without C++11 you can use specialisation, if all your dimensions have the same type:
template <typename T, unsigned nest>
struct Bin {
std::vector<Bin<T, (nest-1)> > bins;
};
template <typename T>
struct Bin<T,0> {
T content;
};
You can only specify the dimension at runtime to a certain degree. If it is bound by a fixed value you can select the appropriate type even dynamically. However, consider using a one-dimensional vector instead of a multi-dimensional jagged vector!
To get the exact syntax you proposed, do:
template <typename T>
class Bin
{
float minRange, maxRange;
std::vector<T> bins;
};
And it should do exactly what you put in your question:
Bin< Bin< Bin<Obj> > > bins;
To do it dynamically (at runtime), I employed some polymorphism. The example is a bit complex. First, there is a base type.
template <typename T>
class BinNode {
public:
virtual ~BinNode () {}
typedef std::shared_ptr< BinNode<T> > Ptr;
virtual T * is_object () { return 0; }
virtual const T * is_object () const { return 0; }
virtual Bin<T> * is_vector() { return 0; }
const T & operator = (const T &t);
BinNode<T> & operator[] (unsigned i);
};
BinNode figures out if the node is actually another vector, or the object.
template <typename T>
class BinObj : public BinNode<T> {
T obj;
public:
T * is_object () { return &obj; }
const T * is_object () const { return &obj; }
};
BinObj inherits from BinNode, and represents the object itself.
template <typename T>
class Bin : public BinNode<T> {
typedef typename BinNode<T>::Ptr Ptr;
typedef std::map<unsigned, std::shared_ptr<BinNode<T> > > Vec;
const unsigned dimension;
Vec vec;
public:
Bin (unsigned d) : dimension(d) {}
Bin<T> * is_vector() { return this; }
BinNode<T> & operator[] (unsigned i);
};
Bin is the vector of BinNode's.
template <typename T>
inline const T & BinNode<T>::operator = (const T &t) {
if (!is_object()) throw 0;
return *is_object() = t;
}
Allows assignment to a BinNode if it is actually the object;
template <typename T>
BinNode<T> & BinNode<T>::operator[] (unsigned i) {
if (!is_vector()) throw 0;
return (*is_vector())[i];
}
Allows the BinNode to be indexed if it is a vector.
template <typename T>
inline BinNode<T> & Bin<T>::operator[] (unsigned i)
{
if (vec.find(i) != vec.end()) return *vec[i];
if (dimension > 1) vec[i] = Ptr(new Bin<T>(dimension-1));
else vec[i] = Ptr(new BinObj<T>);
return *vec[i];
}
Returns the indexed item if it is present, otherwise creates the appropriate entry, depending on the current dimension depth. Adding a redirection operator for pretty printing:
template <typename T>
std::ostream &
operator << (std::ostream &os, const BinNode<T> &n) {
if (n.is_object()) return os << *(n.is_object());
return os << "node:" << &n;
}
Then you can use Bin like this:
int dim = 3;
Bin<float> v(dim);
v[0][1][2] = 3.14;
std::cout << v[0][1][2] << std::endl;
It doesn't currently support 0 dimension, but I invite you to try to do it yourself.
Related
I have a template class method
template<class T>
T pop<T>();
Now I want to do a template specialization as follows,
template<class T>
std::vector<T> pop<T>();
I can do the following no problem,
template<>
std::vector<int> classname::pop<std::vector<int>>();
But I still need to leave the type as a template parameter. How do I accomplish this?
Off the top of my head, I usually get around it by using a one-member struct:
template <typename T>
struct pop_impl {
static T pop(classname& x); // normal function
};
template <typename T>
struct pop_impl<std::vector<T>> {
static std::vector<T> pop(classname& x); // specialized for std::vector<T>
};
template <typename T>
T classname::pop() { return pop_impl<T>::pop(*this); }
This answer was originally provided by Austin Salgat in the body of the question Template Specialization for T -> std::vector, (posted under the CC BY-SA 3.0 license), and has been moved here as an answer in order to adhere to the site's Q&A format.
Thanks to Piotr I ended up using tag dispatching. Below is the code
for what I ended up doing,
// The public method that is accessed by class.push<std::vector<int>>(12);
template<class T>
void push(T data) {
push(tag<T>(), data);
}
// The private method that calls the actual vector push for vector types
template<class T>
void push(tag<std::vector<T>>, std::vector<T> const& data_vector) {
push_vector(data_vector);
}
// The actual implementation
template<class T>
void push_vector(std::vector<T> const& data_vector) {
// Actual implementation in here
}
A possible solution is a non-member function implemented like this
template <class T>
struct classname_pop
{
static T pop(classname &obj) { return obj.pop() ;}
}
template <class T>
struct classname_pop<std::vector<T>>
{
static std::vector<T> pop(classname &obj) {obj.specialized_pop() ;}
}
template <class T>
T classname_pop(classname &obj)
{
return classname_pop_t<T>::pop() ;
}
You need a temporary proxy to dispatch to different results:
Example:
#include <algorithm>
#include <iostream>
#include <vector>
class Stack
{
private:
std::vector<int> m_data;
class Pop {
friend class Stack;
public:
Stack& stack;
Pop(Stack& stack)
: stack(stack)
{}
private:
Pop(const Pop&) = default;
Pop& operator = (const Pop&) = default;
public:
operator int () {
std::vector<int>& data = stack.m_data;
int result = -1;
if( ! data.empty()) {
result = data.front();
data.erase(data.begin());
}
return result;
}
operator std::vector<int> () {
std::vector<int>& data = stack.m_data;
std::size_t size = std::min(data.size(), std::size_t(3));
std::vector<int> result(data.begin(), data.begin() + size);
data.erase(data.begin(), data.begin() + size);
return result;
}
};
public:
Stack()
: m_data( {0, 1, 2, 3, 4, 5, 6, 7, 8} )
{}
const std::vector<int>& data() const { return m_data; }
Pop pop() { return Pop(*this); }
};
int main()
{
Stack stack;
int i = stack.pop();
std::vector<int> v = stack.pop();
std::cout << "i = " << i << '\n';
std::cout << "v = {";
for(auto i : v)
std::cout << i;
std::cout << "}\n";
}
Disclaimer: I consider the code totally useless (It might become useful if there is a pop() just returning a single value and a pop(std::size_t) converting to different containers, where the destructor of Pop is doing the erase).
The code below allows me to template a function
taking a parameter which is a vector of one of three different pointer types to Box objects:
const std::vector<std::shared_ptr<Box>>&
const std::vector<std::weak_ptr<Box>>&
const std::vector<Box*>&
Is there a way to extend this to support:
const vector<Box>&
const vector<std::reference_wrapper<Box>>
perhaps something in boost?
#include <vector>
#include <iostream>
class Box{
public:
Box (unsigned int id, unsigned int side): id(id), side(side){}
int volume(){
return side * side * side;
}
unsigned int id;
unsigned int side;
};
template <typename T>
struct is_box_containter {
enum { value = false };
};
template <>
struct is_box_containter <std::vector<std::shared_ptr<Box>>> {
enum { value = true };
};
template <>
struct is_box_containter <std::vector<std::weak_ptr<Box>>> {
enum { value = true };
};
template <>
struct is_box_containter <std::vector<Box*>> {
enum { value = true };
};
template <typename T>
typename std::enable_if<is_box_containter<T>::value>::type
measure(T const& boxes )
{
for (auto& box : boxes) {
std::cout << box->id << " has volume " << box->volume() << std::endl;
}
}
int main (){
std::vector<std::shared_ptr<Box>> some_boxes;
some_boxes.push_back(std::shared_ptr<Box>(new Box(1,4)));
some_boxes.emplace_back(new Box(2, 12));
Box * box_3 = new Box(3, 8);
Box * box_4 = new Box(4, 9);
std::vector<Box*> more_boxes;
more_boxes.emplace_back(box_3);
more_boxes.emplace_back(box_4);
measure(some_boxes);
measure(more_boxes);
return 0;
}
Why I am asking this question:
I have an application with two functions which implement near identical logic. One takes a list of SomeClass, the other takes a vector of pointers to SomeClass.
I am currently planning on refactoring the code to replace the list of SomeClass with a list of shared pointers to SomeClass. But the only reason I am doing this is to move the logic to a common implementation. I don't want to do that if there is a perfectly reasonable way to avoid it.
If I understood your question correctly, you could use a dereferencing mechanism like below:
template<typename T>
T& dereference(T &v) {
return v;
}
template<typename T>
const T& dereference(const T& v) {
return v;
}
template<typename T>
typename std::enable_if<!std::is_function<T>::value, T&>::type dereference(T* v) {
return dereference(*v);
}
template<typename T>
const T& dereference(const std::shared_ptr<T>& v) {
return dereference(*v);
}
template<typename T>
const T& dereference(const std::weak_ptr<T>& v) {
return dereference(*v);
}
template<typename T>
const T& dereference(const std::reference_wrapper<T>& v) {
return v;
}
and then call your data like:
template <typename T>
typename std::enable_if<is_box_containter<T>::value>::type
measure(T const& boxes )
{
for (auto& box : boxes) {
std::cout << dereference(box).id
<< " has volume " << dereference(box).volume() << std::endl;
}
}
LIVE DEMO
P.S You'll also have to define:
template <>
struct is_box_containter <std::vector<Box>> {
enum { value = true };
};
template <>
struct is_box_containter <std::vector<std::reference_wrapper<Box>>> {
enum { value = true };
};
I have a template class method
template<class T>
T pop<T>();
Now I want to do a template specialization as follows,
template<class T>
std::vector<T> pop<T>();
I can do the following no problem,
template<>
std::vector<int> classname::pop<std::vector<int>>();
But I still need to leave the type as a template parameter. How do I accomplish this?
Off the top of my head, I usually get around it by using a one-member struct:
template <typename T>
struct pop_impl {
static T pop(classname& x); // normal function
};
template <typename T>
struct pop_impl<std::vector<T>> {
static std::vector<T> pop(classname& x); // specialized for std::vector<T>
};
template <typename T>
T classname::pop() { return pop_impl<T>::pop(*this); }
This answer was originally provided by Austin Salgat in the body of the question Template Specialization for T -> std::vector, (posted under the CC BY-SA 3.0 license), and has been moved here as an answer in order to adhere to the site's Q&A format.
Thanks to Piotr I ended up using tag dispatching. Below is the code
for what I ended up doing,
// The public method that is accessed by class.push<std::vector<int>>(12);
template<class T>
void push(T data) {
push(tag<T>(), data);
}
// The private method that calls the actual vector push for vector types
template<class T>
void push(tag<std::vector<T>>, std::vector<T> const& data_vector) {
push_vector(data_vector);
}
// The actual implementation
template<class T>
void push_vector(std::vector<T> const& data_vector) {
// Actual implementation in here
}
A possible solution is a non-member function implemented like this
template <class T>
struct classname_pop
{
static T pop(classname &obj) { return obj.pop() ;}
}
template <class T>
struct classname_pop<std::vector<T>>
{
static std::vector<T> pop(classname &obj) {obj.specialized_pop() ;}
}
template <class T>
T classname_pop(classname &obj)
{
return classname_pop_t<T>::pop() ;
}
You need a temporary proxy to dispatch to different results:
Example:
#include <algorithm>
#include <iostream>
#include <vector>
class Stack
{
private:
std::vector<int> m_data;
class Pop {
friend class Stack;
public:
Stack& stack;
Pop(Stack& stack)
: stack(stack)
{}
private:
Pop(const Pop&) = default;
Pop& operator = (const Pop&) = default;
public:
operator int () {
std::vector<int>& data = stack.m_data;
int result = -1;
if( ! data.empty()) {
result = data.front();
data.erase(data.begin());
}
return result;
}
operator std::vector<int> () {
std::vector<int>& data = stack.m_data;
std::size_t size = std::min(data.size(), std::size_t(3));
std::vector<int> result(data.begin(), data.begin() + size);
data.erase(data.begin(), data.begin() + size);
return result;
}
};
public:
Stack()
: m_data( {0, 1, 2, 3, 4, 5, 6, 7, 8} )
{}
const std::vector<int>& data() const { return m_data; }
Pop pop() { return Pop(*this); }
};
int main()
{
Stack stack;
int i = stack.pop();
std::vector<int> v = stack.pop();
std::cout << "i = " << i << '\n';
std::cout << "v = {";
for(auto i : v)
std::cout << i;
std::cout << "}\n";
}
Disclaimer: I consider the code totally useless (It might become useful if there is a pop() just returning a single value and a pop(std::size_t) converting to different containers, where the destructor of Pop is doing the erase).
I have a templated class with the template argument the number of dimensions of some datapoints the class shall save. This class has a specialized version MyClass<-1> that allows for dimensions not known at compile time.
How can I cast a specific class (say MyClass<2>) to this more general form?
To be a bit more concrete, here is some artificial example that shows the situation. (I use the Eigen library, but I suppose for the general principle this should not matter)
using namespace Eigen;
template <std::size_t dim>
class MyClass {
public:
// Some constructors...
// A sample function:
Matrix<double, dim, 1> returnPoint();
// Some more functions here
private:
Matrix<double, dim, 1> point;
}
Now, suppose I have the following code segment:
MyClass<2> *foo;
MyClass<Dynamic> *bar; // Dynamic is a Eigen constant, being defined as -1
// Do something here
// How to do this:
bar = some_cast<MyClass<Dynamic> *>(foo);
Thinking about the problem I suppose what I want is impossible to archive without actually copying the values of point. Anybody able to prove me wrong or confirm this assumption?
It is possible to achieve the casting without actually copying the values but only if you have been careful make it work.
When you instantiate a class template with two different sets of arguments you get two distinct classes that are not related. Unless you specifically define one to inherit from the other, for example:
namespace with_inheritance {
template <class T, long sz>
class vector : public vector<T,-1> {
typedef vector<T,-1> base_t;
public:
vector() : base_t (sz) { }
};
template <class T>
class vector<T, -1> {
T* v_;
size_t sz_;
public:
vector(size_t sz) : v_ (new T[sz]), sz_ (sz) { }
~vector() { delete [] v_; }
T& operator[](size_t i)
{
if (i >= sz_) throw i;
return v_[i];
}
};
} // with_inheritance
So in this case you can cast as in:
namespace wi = with_inheritance;
wi::vector<double, 10> v;
wi::vector<double, -1>* p = &v;
std::cout << (*p)[1] << '\n';
Without the inheritance relationship casting between them will not be permitted. You can, however, use reinterpret_cast to get around the type system when you want to. But you have be very careful that the objects have identical layout and invariants to make sure everthing will work ok. As in:
namespace with_lots_of_care {
template <class T, long sz>
class vector {
T* v_;
size_t sz_;
public:
vector() : v_ (new T[sz]), sz_ (sz) { }
~vector() { delete [] v_; }
T& operator[](size_t i)
{
if (i >= sz_) throw i;
return v_[i];
}
};
template <class T>
class vector<T, -1> {
T* v_;
size_t sz_;
public:
vector(size_t sz) : v_ (new T[sz]), sz_ (sz) { }
~vector() { delete [] v_; }
T& operator[](size_t i)
{
if (i >= sz_) throw i;
return v_[i];
}
};
} // with_lots_of_care
And then cast as in:
namespace wc = with_lots_of_care;
wc::vector<double, 10> v;
wc::vector<double, -1>* p = reinterpret_cast<wc::vector<double, -1>*>(&v);
std::cout << (*p)[1] << '\n';
I'd like to write an n-dimensional histogram class. It should be in the form of bins that contains other bins etc. where each bin contains min and max range, and a pointer to the next dimension bins
a bin is defined like
template<typename T>
class Bin {
float minRange, maxRange;
vector<Bin<either Bin or ObjectType>> bins;
}
This definition is recursive. So in run time the user defines the dimension of the histogram
so if its just 1-dimension, then
Bin<Obj>
while 3-dimensions
Bin<Bin<Bin<Obj>>>
Is this possible?
Regards
Certainly, C++11 has variable length parameter lists for templates. Even without C++11 you can use specialisation, if all your dimensions have the same type:
template <typename T, unsigned nest>
struct Bin {
std::vector<Bin<T, (nest-1)> > bins;
};
template <typename T>
struct Bin<T,0> {
T content;
};
You can only specify the dimension at runtime to a certain degree. If it is bound by a fixed value you can select the appropriate type even dynamically. However, consider using a one-dimensional vector instead of a multi-dimensional jagged vector!
To get the exact syntax you proposed, do:
template <typename T>
class Bin
{
float minRange, maxRange;
std::vector<T> bins;
};
And it should do exactly what you put in your question:
Bin< Bin< Bin<Obj> > > bins;
To do it dynamically (at runtime), I employed some polymorphism. The example is a bit complex. First, there is a base type.
template <typename T>
class BinNode {
public:
virtual ~BinNode () {}
typedef std::shared_ptr< BinNode<T> > Ptr;
virtual T * is_object () { return 0; }
virtual const T * is_object () const { return 0; }
virtual Bin<T> * is_vector() { return 0; }
const T & operator = (const T &t);
BinNode<T> & operator[] (unsigned i);
};
BinNode figures out if the node is actually another vector, or the object.
template <typename T>
class BinObj : public BinNode<T> {
T obj;
public:
T * is_object () { return &obj; }
const T * is_object () const { return &obj; }
};
BinObj inherits from BinNode, and represents the object itself.
template <typename T>
class Bin : public BinNode<T> {
typedef typename BinNode<T>::Ptr Ptr;
typedef std::map<unsigned, std::shared_ptr<BinNode<T> > > Vec;
const unsigned dimension;
Vec vec;
public:
Bin (unsigned d) : dimension(d) {}
Bin<T> * is_vector() { return this; }
BinNode<T> & operator[] (unsigned i);
};
Bin is the vector of BinNode's.
template <typename T>
inline const T & BinNode<T>::operator = (const T &t) {
if (!is_object()) throw 0;
return *is_object() = t;
}
Allows assignment to a BinNode if it is actually the object;
template <typename T>
BinNode<T> & BinNode<T>::operator[] (unsigned i) {
if (!is_vector()) throw 0;
return (*is_vector())[i];
}
Allows the BinNode to be indexed if it is a vector.
template <typename T>
inline BinNode<T> & Bin<T>::operator[] (unsigned i)
{
if (vec.find(i) != vec.end()) return *vec[i];
if (dimension > 1) vec[i] = Ptr(new Bin<T>(dimension-1));
else vec[i] = Ptr(new BinObj<T>);
return *vec[i];
}
Returns the indexed item if it is present, otherwise creates the appropriate entry, depending on the current dimension depth. Adding a redirection operator for pretty printing:
template <typename T>
std::ostream &
operator << (std::ostream &os, const BinNode<T> &n) {
if (n.is_object()) return os << *(n.is_object());
return os << "node:" << &n;
}
Then you can use Bin like this:
int dim = 3;
Bin<float> v(dim);
v[0][1][2] = 3.14;
std::cout << v[0][1][2] << std::endl;
It doesn't currently support 0 dimension, but I invite you to try to do it yourself.