Return type errors for double templated function

Quick run-down.

Here is the assignment: https://drive.google.com/file/d/0B-t5ghDb_TCqRDVJekFrX3M5bGM/view?pref=2&pli=1

Here is the main for testing: https://drive.google.com/file/d/0B-t5ghDb_TCqY2xHdVFFRzdBWUE/view?pref=2&pli=1

I've done most of it already but I've run into an error I can't figure out. Here is my Ntree.h file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#ifndef NTREE_H
#define NTREE_H

#include <vector>

template <class T>
class Ntree
{
    public:

        template <class U>
        struct node
        {
            U value;
            std::vector<node<U>* > children;

            node(const U& val)
            {
                value = val;
            }

            Ntree<T>::node<U>* addChild(const U& val);

        };

        Ntree(): root(0){}
        Ntree(const T& val)
        {
            root->value = val;
        }

        node<T>* getRoot(){ return root; }

        bool operator==(const Ntree<T>& rhs);

        void serialize (const char* filepath);

    private:
        node<T>* root;
        T value;

};

#endif // NTREE_H 


And here is my Ntree.cpp file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "Ntree.h"

#include <iostream>
#include <fstream>

template <class T, class U>
Ntree<T>::node<U>* Ntree<T>::node<U>::addChild(const U& val)
{
    node<U>* child = new node(val);
    children.push_back(child);

    return child;
}

template <class T>
bool Ntree<T>::operator==(const Ntree<T>& rhs)
{
    return root->value == rhs.root->value;
}

template <class T>
void Ntree<T>::serialize (const char* filepath)
{
    std::ofstream outfile(filepath);
    int i = 0;

    while(root)
    {
        outfile << root;
        while(i < root->children.size())
        {
            outfile << root->children[i];
            i++;
        }
        outfile << ".";
    }
}



I get the following 3 errors for line 11:

error: non-template 'node' used as template.
note: use 'Ntree<T>:: template node' to indicate that it is a template.
error: need 'typename' before 'Ntree<T>::node' because 'Ntree<T>' is a dependent scope.

I have no idea why im getting these errors. Any help?
Last edited on
Why is node a nested template?

Wouldn't something like this suffice?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <vector>

template < typename T > struct Ntree
{
    struct node
    {
       T value;
       std::vector< node* > children;

       node( const T& val ) : value(val) {} ;
       ~node() { for( auto p : children ) delete p ; }
       // etc.

       node* addChild( const T& val )
       {
           children.push_back( new node(val) ) ;
           return children.back() ;
       }
       
       // ...
    };

    Ntree(): root(nullptr){}
    Ntree( const T& val ) : root( new node(val) ) {}
    ~Ntree() { delete root ; }
    // etc.

    node* getRoot() { return root; }

    bool operator==(const Ntree<T>& rhs); // to do

    void serialize (const char* filepath); // to do
    
    // ...

    private: node* root ;
};

#include <string>

int main() {

    Ntree<std::string> tree("Food");
    using node = Ntree<std::string>::node ;

	node* a = tree.getRoot()->addChild("Plant");
	node* b = tree.getRoot()->addChild("Animal");
	node* c = a->addChild("Roots");
	node* d = a->addChild("Leaves");
	node* e = a->addChild("Fruits");
	node* f = b->addChild("Fish");
	node* g = b->addChild("Mammals");
	node* h = b->addChild("Birds");

    // ...
}
Okay, so here is my updated header file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#ifndef NTREE_H
#define NTREE_H

#include <vector>

template <class T>
class Ntree
{
    public:

        struct node
        {
            T value;
            std::vector<node*> children;

            node(const T& val): value(val){}

            Ntree<T>::node* addChild(const T& val);

        };

        Ntree(): root(0){}
        Ntree(const T& val): root(new node(val)){}

        node* getRoot(){ return root; }

        bool operator==(const Ntree<T>& rhs);

        void serialize (const char* filepath);

    private:
        node* root;
};

#endif // NTREE_H 


And here is my updated .cpp file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "Ntree.h"

#include <iostream>
#include <fstream>

template <class T>
Ntree<T>::node* Ntree<T>::node::addChild(const T& val)
{
    node* child = new node(val);
    children.push_back(child);

    return child;
}

template <class T>
bool Ntree<T>::operator==(const Ntree<T>& rhs)
{
    return root->value == rhs.root->value;
}

template <class T>
void Ntree<T>::serialize (const char* filepath)
{
    std::ofstream outfile(filepath);
    int i = 0;

    while(root)
    {
        outfile << root;
        while(i < root->children.size())
        {
            outfile << root->children[i];
            i++;
        }
        outfile << ".";
    }
}


Your suggestions have cut down my number of errors, so thank you. But Im still getting this one error for line 7 in my .cpp file

error: need 'typename' before 'Ntree<T>::node' because 'Ntree<T>' is a dependent scope.

Apparently there is something wrong with my return type. Any help on this?
UPDATE:

So I literally had to write the word 'typename' before my return type on line 7. That fixed the issue (but now I am dealing with other errors). Can anyone explain why this works? I've never had to do this before.
> error: need 'typename' before 'Ntree<T>::node' because 'Ntree<T>' is a dependent scope.

See: http://www.cplusplus.com/forum/beginner/103508/#msg557627

You may want to read: 'Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?' in https://isocpp.org/wiki/faq/templates
^Interesting read.

So I have to move all my function definitions into my header file? And remove my .cpp file altogether?
There are two way I know.
First way is put definition in .h file and remove .cpp.
The other way is define function in .cpp file and include ".cpp" when you used it
Last edited on
Need help serializing this N-ary tree into a file.

The function call in main looks like this: tree.serialize("foodtree.out");

I stored the N children of the tree in a vector called 'children'. Even though I declared 'children' publicly in a struct within the class, my compiler says it is not within scope when I try to use it in my serialize and serializeRec function. Any idea why this is happening?

Here is my .h file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#ifndef NTREE_H
#define NTREE_H

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

template <class T>
class Ntree
{
    public:

        struct tnode
        {
            T value;
            std::vector<tnode*> children;

            tnode(const T& val): value(val){}

            tnode* addChild(const T& val)
            {
                tnode* child = new tnode(val);
                children.push_back(child);

                return child;
            }

        };

        Ntree(): root(0){}
        Ntree(const T& val): root(new tnode(val)){}

        tnode* getRoot(){ return root; }

        bool operator==(const Ntree<T>& rhs)
        {
            return root->value == rhs.root->value;
        }

        // Here is my serialize function
        void serialize (const char* filepath)
        {
            std::ofstream outfile(filepath);
            serializeRec(root);

        }

       //  im using cout for now just so I can see the output
      // This is where im getting error: 'children' was not declared in this scope
        void serializeRec(tnode* root)
        {
            if(!root) return;

            cout << root->value << endl;
            for(int i=0; i<children.size() && root->children[i]; ++i)
            {
               serializeRec(root->children[i]);
            }

            cout << "#" << endl;

        }

    private:
        tnode* root;
};

#endif // NTREE_H 
I have made some progress but still have a few bugs to fix. I am still trying to make my serialize function, so please focus on that.

Here is my main (given by professor)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// author: Arslan
// CISC 3130 Spring 2016
// Program #3 main for testing

#include <assert.h>
#include <iostream>
#include <string>

#include "Ntree.h"

typedef Ntree<std::string>::tnode node;

int main() {
  Ntree<std::string> tree("Food");		// Create tree with root containing the string "food"

	// Ntree::getRoot() should return a postd::stringer to the tree's root
	// Ntree::node() should have an addChild method that takes a T, allocates a new node with that T as its value, and adds it to the called node's list of children
	node* a = tree.getRoot()->addChild("Plant");
	node* b = tree.getRoot()->addChild("Animal");
	node* c = a->addChild("Roots");
	node* d = a->addChild("Leaves");
	node* e = a->addChild("Fruits");
	node* f = b->addChild("Fish");
	node* g = b->addChild("Mammals");
	node* h = b->addChild("Birds");
	node* i = c->addChild("Potatoes");
	node* j = c->addChild("Carrots");
	node* k = d->addChild("Lettuce");
	node* l = d->addChild("Cabbage");
	node* m = e->addChild("Apples");
	node* n = e->addChild("Pears");
	node* o = e->addChild("Plums");
	node* p = e->addChild("Grapes");
	node* q = e->addChild("Oranges");
	node* r = f->addChild("Salmon");
	node* s = f->addChild("Tuna");
	node* t = g->addChild("Beef");
	node* u = g->addChild("Lamb");
	node* v = h->addChild("Chicken");
	node* w = h->addChild("Turkey");
	node* x = r->addChild("Wild");
	node* y = r->addChild("Farm");
	node* z = m->addChild("GrannySmith");
	node* aa = m->addChild("Gala");

	// write toString method
	//std::cout << tree.toString() << std::endl;

	// write serialize method that takes filepath
	tree.serialize("foodtree.out");

	// default constructor creates empty tree.
	Ntree<std::string> tree2;
	// tree2 should become the tree deserialized from filepath
	//tree2.deserialize("foodtree.out");

	assert(tree==tree2);		// overload equality operator
}


Here is my .h file (made by me):
Take a look at some comments I put in here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#ifndef NTREE_H
#define NTREE_H

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;
const int N = 50; // anyway to avoid this global variable?
// If I put it within the class, I get a out of scope error, and I dont know why....


template <class T>
class Ntree
{
    public:

        struct tnode
        {
            T value;
            tnode* children[N];

            tnode(const T& val): value(val){
                for(int i = 0; i<N; ++i)
                    children[i] = 0;
            }

            tnode* addChild(const T& val)
            {
                tnode* child = new tnode(val);
                for(int i = 0; i<N; ++i)
                {
                    if(children[i] == 0)
                    {
                        children[i] = child;
                        break;
                    }
                }

                return child;
            }

        };

        Ntree(): root(0){}
        Ntree(const T& val): root(new tnode(val)){}

        tnode* getRoot(){ return root; }

        bool operator==(const Ntree<T>& rhs)
        {
            return root->value == rhs.root->value;
        }

        void serialize (const char* filepath)
        {
            std::ofstream outfile(filepath);
            serializeRec(root);

        }

        void serializeRec(tnode* root)
        {
            if(!root) return;

            cout << root->value << endl;
            for(int i=0; i<N && root->children[i]; ++i)
            {
               serializeRec(root->children[i]);
            }

            cout << "#" << endl;

        }

    private:
        tnode* root;
};

#endif // NTREE_H 



My serialize function works, in that it prints out what is expected, however, I get a "program.exe. has stopped working" message pop up. So It seems my program crashed after printing the tree.

Here is my output:


Food
Plant
Roots
Potatoes
#
Carrots
#
#
Leaves
Lettuce
#
Cabbage
#
#
Fruits
Apples
GrannySmith
#
Gala
#
#
Pears
#
Plums
#
Grapes
#
Oranges
#
#
#
Animal
Fish
Salmon
Wild
#
Farm
#
#
Tuna
#
#
Mammals
Beef
#
Lamb
#
#
Birds
Chicken
#
Turkey
#
#
#
#

Process returned -1073741819 (0xC0000005)   execution time : 2.233 s
Press any key to continue.



Any idea why my program crashes even though the function seems to work?
In your main, at the very end, I see that you commented out the call to deserialize(), but you did not comment out assert() function, which if you take a look is actually an #include .h file. I am guessing your professor will use that file to check your work? The program seems to work fine if you comment it out for testing.

I would suggest adding in your deserialize funtion, then leave assert() commented out and test to see what happens.
Last edited on
I figured that was it so I made my deserialize function. I've also made my toString function.

However, my assert still seems to fail, and my toString is not working at all:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#ifndef NTREE_H
#define NTREE_H

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;
const int N = 10;


template <class T>
class Ntree
{
    public:

        struct tnode
        {
            T value;
            tnode* children[N];

            tnode(const T& val): value(val){
                for(int i = 0; i<N; ++i)
                    children[i] = 0;
            }

            tnode* addChild(const T& val)
            {
                tnode* child = new tnode(val);
                for(int i = 0; i<N; ++i)
                {
                    if(children[i] == 0)
                    {
                        children[i] = child;
                        break;
                    }
                }

                return child;
            }

        };

        Ntree(): root(0){}
        Ntree(const T& val): root(new tnode(val)){}

        tnode* getRoot(){ return root; }

        void toString()
        {
            toStringRec(this->root);
        }

        void toStringRec(tnode* root)
        {
            if(!root) return;

            cout << root->value << endl;
            for(int i=0; i<N && root->children[i]; ++i)
            {
               serializeRec(root->children[i]);
            }

            cout << "#" << endl;
        }

        /*friend std::ostream& operator<<(std::ostream& os, Ntree<T>& tree)
        {

            if(!tree.root) return os;

            os << tree.root->value << endl;
            for(int i=0; i<N && tree.root->children[i]; ++i)
            {
               serializeRec(tree.root->children[i]);
            }

            os << "#" << endl;
        }*/


        bool operator==(const Ntree<T> rhs)
        {
            cout << "in ==";
            return root->value == rhs.root->value;
        }

        void serialize (const char* filepath)
        {
            std::ofstream outfile(filepath);
            serializeRec(root, outfile);
            outfile.close();
        }

        void serializeRec(tnode* root, std::ofstream& outfile)
        {
            if(!root) return;

            outfile << root->value << endl;
            for(int i=0; i<N && root->children[i]; ++i)
            {
               serializeRec(root->children[i], outfile);
            }

            outfile << "#" << endl;

        }

        void deserialize(const char* filepath)
        {
            cout << "Now in deserialize function...";
            std::ifstream infile(filepath);
            deserializeRec(root, infile);
            infile.close();
            cout << "Now back in deserialize function...";
        }

        bool deserializeRec(tnode* &root, std::ifstream& infile)
        {
            string val;
            if(!(infile >> val) || val == "#")
                return true;

            else
            {
                root = new tnode(val);
                for(int i = 0; i<N; ++i)
                    if(deserializeRec(root, infile))
                        break;
            }

            return false;
        }

    private:
        tnode* root;
};



#endif // NTREE_H 


I've commented out my assertion in main(we'll deal with that later). Right now, my call toString() is giving me an error in main, saying no match for 'operator<<'. Do I need to over the << operator?

Would I overload it as a friend function and define it fully within the .h file?
Last edited on
Okay, so I've updated my .h file. I've now overloaded the << operator. However, its still not working:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#ifndef NTREE_H
#define NTREE_H

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;
const int N = 10;


template <class T>
class Ntree
{
    public:

        struct tnode
        {
            T value;
            tnode* children[N];

            tnode(const T& val): value(val){
                for(int i = 0; i<N; ++i)
                    children[i] = 0;
            }

            tnode* addChild(const T& val)
            {
                tnode* child = new tnode(val);
                for(int i = 0; i<N; ++i)
                {
                    if(children[i] == 0)
                    {
                        children[i] = child;
                        break;
                    }
                }

                return child;
            }

        };

        Ntree(): root(0){}
        Ntree(const T& val): root(new tnode(val)){}

        tnode* getRoot(){ return root; }

        // why isn't this working?
        friend std::ostream& operator<<(std::ostream& os, Ntree<T>& tree)
        {

            if(!tree.root) return os;

            os << tree.root->value << endl;
            for(int i=0; i<N && tree.root->children[i]; ++i)
            {
               return (os << tree.root->children[i]); // recurse on operator << 
            }

            os << "#" << endl;
        }

        void toString()
        {
           cout << this; // calls overloaded << operator
        }


        bool operator==(const Ntree<T> rhs)
        {
            cout << "in ==";
            return root->value == rhs.root->value;
        }

        void serialize (const char* filepath)
        {
            std::ofstream outfile(filepath);
            serializeRec(root, outfile);
            outfile.close();
        }

        void serializeRec(tnode* root, std::ofstream& outfile)
        {
            if(!root) return;

            outfile << root->value << endl;
            for(int i=0; i<N && root->children[i]; ++i)
            {
               serializeRec(root->children[i], outfile);
            }

            outfile << "#" << endl;

        }

        void deserialize(const char* filepath)
        {
            cout << "Now in deserialize function...";
            std::ifstream infile(filepath);
            deserializeRec(root, infile);
            infile.close();
            cout << "Now back in deserialize function...";
        }

        bool deserializeRec(tnode* &root, std::ifstream& infile)
        {
            string val;
            if(!(infile >> val) || val == "#")
                return true;

            else
            {
                root = new tnode(val);
                for(int i = 0; i<N; ++i)
                    if(deserializeRec(root, infile))
                        break;
            }

            return false;
        }

    private:
        tnode* root;
};

#endif // NTREE_H 


Notice that my << overload is a friend (is that fine) and defined fully within the .h file (is that also fine?).

Last edited on
I've also tried using stringstreams, but im still getting an error:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        std::string toString()
        {
           std::stringstream str;
           return(this->root, str);
        }

        std::string toStringRec(tnode* root, std::stringstream& str)
        {
            if(!root) return str.str();

            str << root->value << endl;
            for(int i=0; i<N && root->children[i]; ++i)
            {
               toStringRec(root->children[i], str);
            }

            str << "#" << endl;
        }


error: could not convert '(0, str)' from 'std::stringstream' to 'std::string'

What am I doing wrong??
Okay, I got my toString function to work.

So currently, only my deserialization is not working, which is also causing my assertion to fail.

Someone please take a look at my deserialize function and let me know what im doing wrong?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#ifndef NTREE_H
#define NTREE_H

#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>

using namespace std;
const int N = 10;


template <class T>
class Ntree
{
    public:

        struct tnode
        {
            T value;
            tnode* children[N];

            tnode(const T& val): value(val){
                for(int i = 0; i<N; ++i)
                    children[i] = 0;
            }

            tnode* addChild(const T& val)
            {
                tnode* child = new tnode(val);
                for(int i = 0; i<N; ++i)
                {
                    if(children[i] == 0)
                    {
                        children[i] = child;
                        break;
                    }
                }

                return child;
            }

        };

        Ntree(): root(0){}
        Ntree(const T& val): root(new tnode(val)){}

        tnode* getRoot(){ return root; }

        std::string toString()
        {
           std::stringstream str;
           toStringRec(this->root, str);
            return str.str();
        }

        void toStringRec(tnode* root, std::stringstream& str)
        {
            if(!root) return;

            str << root->value << endl;
            for(int i=0; i<N && root->children[i]; ++i)
            {
               toStringRec(root->children[i], str);
            }

            str << "#" << endl;
        }


        bool operator==(const Ntree<T> rhs)
        {
            return root->value == rhs.root->value;
        }

        void serialize (const char* filepath)
        {
            std::ofstream outfile(filepath);
            serializeRec(root, outfile);
            outfile.close();
        }

        void serializeRec(tnode* root, std::ofstream& outfile)
        {
            if(!root) return;

            outfile << root->value << endl;
            for(int i=0; i<N && root->children[i]; ++i)
            {
               serializeRec(root->children[i], outfile);
            }

            outfile << "#" << endl;

        }

        void deserialize(const char* filepath)
        {
            std::ifstream infile(filepath);
            deserializeRec(root, infile);
            infile.close();
        }
         // why isn't this function working?
        int deserializeRec(tnode* root, std::ifstream& infile)
        {
            string val;
            if(!(infile >> val) || val == "#")
                return 1;

            else
            {
                root = new tnode(val);
                for(int i = 0; i<N; ++i)
                    if(deserializeRec(root, infile))
                        break;
            }

            return 0;
        }

    private:
        tnode* root;
};

Never mind, got my program to work fine now.
Topic archived. No new replies allowed.