On Jun 24, 10:01 pm, mark.te...@gmail.com wrote:
I don't think there is any good way in C++ to do exactly what you want
(have the function take a varying number of arguments based on a
template). However you can obtain nearly the same result by requiring
each of the AlleleTraits to have an internal "initializer" object.
Then instead of passing in different numbers of parameters you can
pass in different initializers ( see code below ).
---------------
// no definition for generic type
template <typename T>
class AlleleTraits {};
// partial specialization for boolean type
template<>
struct AlleleTraits<bool{
struct initializer {};
static bool randomize(const initializer& val) {
return flip(0.5);
}
};
// partial specialization for integer type
template<>
struct AlleleTraits<int{
typedef int initializer;
static int randomize(const initializer& k) {
return rnd(0, k-1);
}
};
// partial specialization for double type
template<>
struct AlleleTraits<double{
struct initializer
{
initializer(double l, double h) { low = l; high = h; }
double low, high;
};
static double randomize(const initializer& init) {
return rnd(low, high);
}
};
// RandomContainer class
template <
typename T,
class Container = vector<T>,
class TTraits = AlleleTraits<T
struct RandomContainer : public Container {
typedef typename Container::iterator iterator;
typedef typename AlleleTraits<T>::initializer initializer;
RandomContainer(size_t size) : Container(size) {}
void initialize(const initializer& v) {
for(unsigned int i=0; i<this->size(); ++i) {
this->operator[](i) = TTraits::randomize(v);
}
}
void print() {
for(unsigned int i=0; i<this->size(); ++i) {
cout<<" "<<this->at(i);
}
}
};
// main.cxx
....
RandomContainer<booltest(6);
test.initialize(AlleleTraits<bool>::initializer()) ;
test.print();
RandomContainer<inttest2(6);
test2.initialize(AlleleTraits<int>::initializer(2) );
test2.print();
RandomContainer<doubletest3(6);
test3.initialize(AlleleTraits<double>::initializer (.2, .5));
test3.print();
....
Hopefully that's more or less what your are looking for,
Mark
Mark, thanks for replying, I like your solution. This is what I came
up with before reading yours:
template <typename T>
class AlleleTraits {}
;
template<>
struct AlleleTraits<bool{
static bool randomize() {
return flip(0.5);
}
};
template<>
struct AlleleTraits<int{
static int low_;
static int high_;
static int randomize() {
return rnd(low_, high_-1);
}
static int cardinality() {
return high_ - low_;
}
static void setLimits(int low, int high) {
low_ = low;
high_ = high;
}
};
int AlleleTraits<int>::low_;
int AlleleTraits<int>::high_ = 2;
template<>
struct AlleleTraits<double{
static double low_;
static double high_;
static double randomize() {
return rnd(AlleleTraits<double>::low_,
AlleleTraits<double>::high_);
}
static void setLimits(double low, double high) {
low_ = low;
high_ = high;
}
static double range() {
return high_ - low_;
}
};
double AlleleTraits<double>::low_;
double AlleleTraits<double>::high_ = 1;
template <
typename T,
class Container = std::vector<T>,
class TTraits = AlleleTraits<T>
>
struct RandomContainer : public Container {
typedef T ValueType;
typedef typename Container::iterator Iterator;
RandomContainer(size_t size) : Container(size) {}
static void setLimits(T low, T high) {
AlleleTraits<T>::setLimits(low,high);
}
void initialize() {
for(int i=0; i<this->size(); ++i) {
this->operator[](i) = TTraits::randomize();
}
}
void print() {
for(int i=0; i<this->size(); ++i) {
cout<<" "<<this->at(i);
}
}
};
// main.cxx
// ...
RandomContainer<booltest0(10);
test0.initialize();
test0.print();
RandomContainer<inttest(10);
RandomContainer<int>::setLimits(3,9);
test.initialize();
test.print();
RandomContainer<doubletest2(10);
RandomContainer<double>::setLimits(0.22,9.333);
test2.initialize();
test2.print();
// ...
0 1 0 0 0 1 1 0 1 0
5 4 5 4 8 7 3 3 7 7
0.368547 2.43343 1.47059 7.54846 1.64782 3.87381 1.40278 1.21157
9.3232 2.20898
However, I will change it so the RandomContainer definition takes
another template parameter and I won't provide a default value for it
(I think the behavior of the container has to be something that the
client has to specify in a single statement and completely). As a
matter of fact, your solution could enter here quite nicely:
template <
typename T,
TTraits::initializer,
class Container = std::vector<T>,
class TTraits = AlleleTraits<T>
>
struct RandomContainer : public Container {
//...
};
The thing is that this code has to be written by the client, and I
want to make it as easy as possible. So, I don't know yet how to
implement this because I don't want the client to write code like the
following:
typedef RandomContainer<double, AlleleTraits<double>::initializer>
doubleContainer;
I will definitely keep the static variables within the AlleleTraits
classes though. Maybe writing a macro that expands the previous code
would be a solution to make the code simpler to the client? I don't
know. Any other ideas?
aČ