473,394 Members | 1,866 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

is there a simple solution to this template problem?

Hi everyone,

The idea is quite simple: generate a container with random values in
it. For that, I decided to create a class that I called
RandomContainer that inherits from a container (with default value
std::vector<T>). To handle the different ways that the values are
randomized, I created a traits class. The problem that I have, is that
the function randomize() within the traits class takes different
parameters depending on the type (bool takes none, int takes one
parameter and double takes two parameters). Is there a way to make
this function randomize() a generic function? How do I handle the
different parameters? The code is as follows:

// no definition for generic type
template <typename T>
class AlleleTraits {};

// partial specialization for boolean type
template<>
struct AlleleTraits<bool{

static bool randomize() {
return flip(0.5);
}
};

// partial specialization for integer type
template<>
struct AlleleTraits<int{

static int randomize(int k) {
return rnd(0, k-1);
}
};

// partial specialization for double type
template<>
struct AlleleTraits<double{

static double randomize(double low, double high) {
return rnd(low, high);
}
};

// RandomContainer class
template <
typename T,
class Container = std::vector<T>,
class TTraits = AlleleTraits<T>
>
struct RandomContainer : public Container {

typedef typename Container::iterator iterator;

RandomContainer(size_t size) : Container(size) {}
void initialize(int k) {
for(int i=0; i<this->size(); ++i) {
this->operator[](i) = TTraits::randomize(k);
}
}

void print() {
for(int i=0; i<this->size(); ++i) {
cout<<" "<<this->at(i);
}
}
};
// main.cxx
....
RandomContainer<inttest(10);
test.initialize(6);
test.print();
....

prints:

1 4 3 1 5 1 4 0 3 1

This is fine because the function randomize(int) was defined within
RandomContainer. If I try to do the same with double or bool I have
compiler errors because of course, those functions are not defined
within the traits class.

Thank you,



Jun 24 '07 #1
7 1994
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

Jun 25 '07 #2
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?



Jun 25 '07 #3
On Jun 25, 1:18 am, aaragon <alejandro.ara...@gmail.comwrote:
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;
Do you mind if they have to write code like this?

typedef RandomContainer<double, AlleleTraitsdoubleContainer;

If not, you can declare RandomContainer like this:
template<typename _T, template<typenameclass _Traits>
class RandomContainer
{
private:
typedef typename _Traits<_T>::initializer _Initializer;
};

Jun 25 '07 #4
Zachary Turner wrote:
>
Do you mind if they have to write code like this?

typedef RandomContainer<double, AlleleTraitsdoubleContainer;

If not, you can declare RandomContainer like this:
template<typename _T, template<typenameclass _Traits>
class RandomContainer
{
private:
typedef typename _Traits<_T>::initializer _Initializer;
};
Actually, you can't declare it as such. You have generated ill-formed
code, as many of your identifiers (_T, _Initializer, and _Traits) are
reserved to the implementation.

Jun 25 '07 #5
On Jun 25, 11:33 am, red floyd <no.s...@here.dudewrote:
Zachary Turner wrote:
Do you mind if they have to write code like this?
typedef RandomContainer<double, AlleleTraitsdoubleContainer;
If not, you can declare RandomContainer like this:
template<typename _T, template<typenameclass _Traits>
class RandomContainer
{
private:
typedef typename _Traits<_T>::initializer _Initializer;
};

Actually, you can't declare it as such. You have generated ill-formed
code, as many of your identifiers (_T, _Initializer, and _Traits) are
reserved to the implementation.
It is true. Besides, I don't think there is a way to include doubles
in constant expressions, so no matter how I try, I won't be able to
initialize everything with a single type definition. I guess the best
approach so far is the one using static functions to set the limits
of the container after its type definition. Any other ideas?

Jun 25 '07 #6
On Jun 25, 12:34 pm, aaragon <alejandro.ara...@gmail.comwrote:
template<typename _T, template<typenameclass _Traits>
class RandomContainer
{
private:
typedef typename _Traits<_T>::initializer _Initializer;
};
Actually, you can't declare it as such. You have generated ill-formed
code, as many of your identifiers (_T, _Initializer, and _Traits) are
reserved to the implementation.

It is true. Besides, I don't think there is a way to include doubles
in constant expressions, so no matter how I try, I won't be able to
initialize everything with a single type definition. I guess the best
approach so far is the one using static functions to set the limits
of the container after its type definition. Any other ideas?- Hide quoted text -
Ok, so remove the underscores and change the name to whatever you
want. Can you give an example that illustrates what you won't be able
to accomplish using the above approach? I'm not sure I follow.

Jun 25 '07 #7
On Jun 25, 1:39 pm, Zachary Turner <divisorthe...@gmail.comwrote:
On Jun 25, 12:34 pm, aaragon <alejandro.ara...@gmail.comwrote:
template<typename _T, template<typenameclass _Traits>
class RandomContainer
{
private:
typedef typename _Traits<_T>::initializer _Initializer;
};
Actually, you can't declare it as such. You have generated ill-formed
code, as many of your identifiers (_T, _Initializer, and _Traits) are
reserved to the implementation.
It is true. Besides, I don't think there is a way to include doubles
in constant expressions, so no matter how I try, I won't be able to
initialize everything with a single type definition. I guess the best
approach so far is the one using static functions to set the limits
of the container after its type definition. Any other ideas?- Hide quoted text -

Ok, so remove the underscores and change the name to whatever you
want. Can you give an example that illustrates what you won't be able
to accomplish using the above approach? I'm not sure I follow.
Well, I was hoping the user to declare everything in the container
with a single line, something like the following:

typedef RandomContainer<double, 0.2, 9.9doubleContainer;
typedef RandomContainer<int, 1, 8intContainer;
typedef RandomContainer<boolboolContainer;

but I don't think something like this is possible because you cannot
use double values in constant expressions. Also, this type definition
is a part of a bigger type definition so I must be able to do this at
compile time. That's why I think the only way to do it is with static
functions to set the limits of the container:

typedef RandomContainer<doubledoubleContainer;
typedef RandomContainer<intintContainer;
typedef RandomContainer<boolboolContainer;

doubleContainer::setLimits(0.2,9.9);
intContainer::setLimits(1,8);

If there is a better way to accomplish the same thing, please let me
know.



Jun 27 '07 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

13
by: Noah Spitzer-Williams | last post by:
Hello guys, I would like to do something seemingly simple: find out if an element in an array that is passed to my function exists. I used to think I could just do: if (arr) ... However, if...
7
by: Leon | last post by:
I'm having a bit of a template-problem, and I was wondering if you guru's know what I'm doing wrong here... I want to create a Vertex class that supports a toPoint() method. Now, in my case...
0
by: Chris F Clark | last post by:
In our C++ project we have some internal bug reporting macros that we use to get useful information when the program does something unexpected. Essentially at the point of the error, we invoke an...
8
by: Ross A. Finlayson | last post by:
I'm trying to write some C code, but I want to use C++'s std::vector. Indeed, if the code is compiled as C++, I want the container to actually be std::vector, in this case of a collection of value...
0
by: 42 | last post by:
I implemented a simple class inherited from Page to create a page template. It simply wraps some trivial html around the inherited page, and puts the inherited page into a form. The problem I...
0
by: ivan.leben | last post by:
I am writing this in a new thread to alert that I found a solution to the problem mentioned here: http://groups.google.com/group/comp.lang.c++/browse_thread/thread/7970afaa089fd5b8 and to avoid...
2
by: Monty | last post by:
Despite reading posts in Google, I don't understand XPATH. Can someone help me write an XPATH. From Google I think my problem is that the default namespace does not have a prefix. I can't change...
8
by: obrianpatrick | last post by:
Hi, I am relatively new to object oriented programming and design. I am developing an application in VS 2005. I am having the following design problem: I have two interfaces X and Y. Y is...
6
by: Christof Warlich | last post by:
Hi, can anyone tell how to convince the compiler to accept the third line in the example below? I need this parameter sequence because I want to define a default argument for T , e.g.:...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.