Jump to content
  • Advertisement
Sign in to follow this  
aaron_ds

Compiler strain/template trouble/infinite iteration

This topic is 5115 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm currently sandboxing around with some template ideas and managed to bork a lot of stuff. I'm using Borland C++ BuilderX. I'm trying to template a return type for a member function. Something like:
template<int length, template<typename> class CONT>
class ARRAY{
    public:
	ARRAY();
	~ARRAY();
	template<typename U>
	U& access(int);
    private:
	CONT data[length];
};

where data is an array of a templated container class with a length of "length". The program actually compiles fine but when I step through the debugger, it goes to the initialization of an ARRAY then calls main(). So now my stack looks like this main() ARRAY<..,..>::ARRAY<..,..>() main() It will just keep loading main() and the constructor over and over again until finally the stack gives up and the program dies. I'm sure the problem is in CONT data[length]; CONT should have some template arguments. I would rather not give it arguments because I want to be able to store all kinds of data in the container. Then I could access them with something like
template<int length, template<typename> class CONT>
template<typename U>
U& ARRAY<length, CONT>::access(int index){
    return reinterpret_cast<U&>(data[index%length].getdata());
}

Naturally that isn't working out very well. Any suggestions? or am I following a path of failure?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by aaron_ds
I would rather not give it arguments because I want to be able to store all kinds of data in the container.


When using a template template parameter in some definition you have to specifiy type arguments, i'm surprised your code even compiles.

Even if you chanage it to normal type parameter it will be a container of some particular type.

Quote:
Original post by aaron_ds
Then I could access them with something like
*** Source Snippet Removed ***
Naturally that isn't working out very well.


I've never seen any STL container that has a "getdata" method, besides there probably isn't any reason to use a cast if your using templated member functions.

Quote:
Original post by aaron_ds
am I following a path of failure?


I think so, i feel there is something your not telling us such as what containers your refering to because like i said no STL container has a getdata method, if you could also say what your exact intentions are we could probably give you a better alternative, you'll need to give a bit more info.

EDIT: Are you sure you need an array of containers? because thats what your is code trying to say.

Share this post


Link to post
Share on other sites
Functions are overloaded by their arguments, not their return values. You can't have a bunch of functions that return different types and all take an integer.

Maybe if CONT had a typedef for whatever type it's using, you could do:

typename CONT::WHATEVER_TYPE & access(int);

For example, STL containers have a ::value_type you could use to find what type of object it contains.

Share this post


Link to post
Share on other sites
Ah, no stl container, just a simple class to encapsulate a templated variable.
I'm suprised it compiles aswell.

I'm attempting to contrive a system to allow for an array of arbitrary types (even more arrays). Thats why I would rather not pass template arguments to the container class. (although this is probably whats causing the problems)

Other than that, its just an exercise in templates. It came out of a need to make a tree that can hold arbitrary types and have any number of children. Though I'm slowly begining to realize that this probably isn't possible in C++. Or atleast I don't quite have the skill level to be able to successfully pull it off.

Share this post


Link to post
Share on other sites
Quote:
Original post by smart_idiot
Functions are overloaded by their arguments, not their return values. You can't have a bunch of functions that return different arguments and all take an integer.


Thats true but for a template functions you can have different return types e.g.:


template < typename Ret >
Ret bar(int i) {
return Ret(i);
}

int main() {

int i = bar<int>(4);

float j = bar<float>(6);

double h = bar<double>(30);


return 0;

}


but as shown the compiler can only deduce template types from function parameters which is not the case in this example so you must explicitly state the type.

Share this post


Link to post
Share on other sites
Quote:
Original post by aaron_ds
Other than that, its just an exercise in templates. It came out of a need to make a tree that can hold arbitrary types and have any number of children. Though I'm slowly begining to realize that this probably isn't possible in C++. Or atleast I don't quite have the skill level to be able to successfully pull it off.


It is possible in a number of ways and its not as complicated as your code is making it out be.

some choices are:

a container of pointers to void (not very safe),
a container of smart pointers to void (a lil-bit more safer),
a container of pointers to some base type (its not really arbitrary types)
a container of boost::any (i'd go with this one).

a quick & safe (not necessary efficient) structure for a heterogeneous n-ary tree with some help with boost libraries:


#include <boost\pool\pool_alloc.hpp>
#include <boost\any.hpp>
#include <boost\smart_ptr.hpp>
#include <list>

template < template < typename U, typename V > class Sequence = std::list >
struct tree {

typedef boost::shared_ptr<tree> tree_node;
typedef boost::pool_allocator<tree_node> node_alloc;
typedef Sequence< tree_node, node_alloc > child_list;

private:

tree* parent;
boost::any val;
child_list kids;

public:

template < typename Tp >
tree(const Tp& b = Tp()): parent(0), kids(), val(b) {}

typename child_list::const_iterator begin() const { return kids.begin(); }

typename child_list::iterator begin() { return kids.begin(); }

typename child_list::const_iterator end() const { return kids.end(); }

typename child_list::iterator end() { return kids.end(); }

typename child_list::size_type size() const { return kids.size(); }

bool empty() const { return kids.empty(); }

};


i leave the rest for you to explore and complete as an exercise [smile] (its late and i'm getting lazy)

boost::pool_allocator
boost::shared_ptr

Share this post


Link to post
Share on other sites
@snk_kid: definatly pointed me in the right direction. ratings++;
I had to change a bit of things around, because boost::shared_ptr doesnt take a template template as its argument.
The data members are fine aswell as the constructor and the empty() method.
However the other methods are causing some problems. (Could be my extreme lack of stl/boost expirence)

eg:
typename child_list::const_iterator begin() const { return kids.begin(); }

I know typename is needed because otherwise child_list::const_iterator would be treated as a static member of child_list. The syntax of the definition looks perfectly fine to me, but I;m getting a nondescript error message of:
F1004 Internal compiler error...
Not very helpful :-/

It does however, seem to work if instead of using a templated class with a container type as a template paramater, that I just hardcode std::list into the class. Although this isn't as generic, it works well enough.
Thanks all.
Cheers!

Share this post


Link to post
Share on other sites
Quote:
Original post by aaron_ds
I had to change a bit of things around, because boost::shared_ptr doesnt take a template template as its argument.


Strange it should do (works with VC++ 7.1 & gcc 3.4.2), i think you'll have to show us what you mean in code, although i did make a lil bo-boo in one of the typedefs it should have been:


typedef boost::shared_ptr< tree< Sequence > > tree_node;


Quote:
Original post by aaron_ds
The data members are fine aswell as the constructor and the empty() method.
However the other methods are causing some problems. (Could be my extreme lack of stl/boost expirence)

eg:
typename child_list::const_iterator begin() const { return kids.begin(); }

I know typename is needed because otherwise child_list::const_iterator would be treated as a static member of child_list. The syntax of the definition looks perfectly fine to me, but I;m getting a nondescript error message of:
F1004 Internal compiler error...
Not very helpful :-/


which compiler & version are you using? VC++ 6.0 is really dodgy for temmplates & the c++ standard support in general.

perhaps if you could post us what you've got so far aswell.

Quote:
Original post by aaron_ds
It does however, seem to work if instead of using a templated class with a container type as a template paramater, that I just hardcode std::list into the class. Although this isn't as generic, it works well enough.


Thats no problem, the reason why i did it in the first place because you could give the client a choice of sequence type containers.

Share this post


Link to post
Share on other sites
This compiles just fine:

#include <oldstl\new.h> //for std::nothrow (dont know why)
#include <boost\pool\pool_alloc.hpp>
#include <boost\any.hpp>
#include <boost\smart_ptr.hpp>
#include <list>

template <template <typename, typename> class Sequence=std::list>
class tree{

typedef boost::shared_ptr<tree<Sequence> > tree_node;
typedef boost::pool_allocator<tree_node> node_alloc;
typedef Sequence<tree_node, node_alloc> child_list;

private:

tree* parent;
boost::any val;
child_list kids;

public:

template < typename Tp >
tree(const Tp& b=Tp()): parent(0), kids(), val(b) {}

typename Sequence::const_iterator begin(void) const{ return kids.begin(); }

typename Sequence::iterator begin() { return kids.begin(); }

typename Sequence::const_iterator end() const { return kids.end(); }

typename Sequence::iterator end() { return kids.end(); }

typename Sequence::size_type size() const { return kids.size(); }

bool empty() const { return kids.empty(); }

};
void food(void){
//it works!!!
tree<> root;
}





For some unknown reason, typename Sequence::const_iterator begin(void) const{ return kids.begin(); }
compiles just fine while anything that would make sense does not.

typename child_list::const_iterator begin(void) const{ return kids.begin(); }
and
typename Sequence<tree_node, node_alloc>::const_iterator begin(void) const{ return kids.begin(); }
both do not compile and give an internal compiling error.

I'm stumped, but it seems to be working.
Thanks again snk_kid, your knowledge of boost and stl is very helpful.

Edit: using Borland C++BuilderX

[Edited by - aaron_ds on October 11, 2004 9:31:50 PM]

Share this post


Link to post
Share on other sites

#include <oldstl\new.h>
#include <boost\pool\pool_alloc.hpp>
#include <boost\any.hpp>
#include <boost\smart_ptr.hpp>
#include <list>
namespace ads{
template <template <typename, typename> class Sequence=std::list>
class tree{
typedef boost::shared_ptr<tree<Sequence> > tree_node;
typedef boost::pool_allocator<tree_node> node_alloc;
typedef Sequence<tree_node, node_alloc> child_list;

private:

tree* parent;
boost::any val;
child_list kids;

public:
/*Public typedef, reduces creation of iterators*/
typedef Sequence<tree_node, node_alloc> child_list;

template <typename Tp >
tree(const Tp& b =Tp() ): parent(0), kids(), val(b) {}

typename Sequence::const_iterator begin(void) const{ return kids.begin(); }

typename Sequence::iterator begin() { return kids.begin(); }

typename Sequence::const_iterator end() const { return kids.end(); }

typename Sequence::iterator end() { return kids.end(); }

typename Sequence::size_type size() const { return kids.size(); }

bool empty() const { return kids.empty(); }

template<typename T>
void add_child(const T& t){
kids.push_back(tree_node(new tree<>(t)));
}

boost::any getdata(void){
return val;
}
};
}



/*Example*/
using boost::any_cast;
typedef ads::tree<> tree;

tree root("root");
root.add_child(1);
root.add_child("subarray");
root.add_child(1.567);


cout<<boost::any_cast<char*>(root.getdata())<<"\n";
tree::child_list::iterator itr=root.begin();



Everything is begining to take shape. I can initialize trees just fine and add data to them aswell.

Accing the data is a bit more complicated than planned.
I publicly typedefed child_list so that I didnt have to type in std::list<boost::shared_ptr<tree<Sequence> >,boost::pool_allocator<boost::shared_ptr<tree<std::list> > > >::iterator
tree::child_list::iterator is less verbose.

There is one problem; however.

tree::child_list::iterator itr=root.begin();
yeild the error Cannot convert '_List_iterator<_Tp,_Nonconst_traits<_Tp> >' to'_List_iterator<boost::shared_ptr<tree>,_Nonconst_triats<boost::shared_ptr<trrr> > >

Perhaps this is because I'm doing
typename Sequence::const_iterator begin(void) const{ return kids.begin(); }
instead of
typename child_list::const_iterator begin() const { return kids.begin(); }

Why would one compile fine and not the other?
The second should compiler better than the former.
What gives?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!