Vector iterator and reading in value from file

I am trying to create a vector iterator from the vector stl, but for the type I am using a class that holds a key value pair, like so

1
2
3
4
5
6
7
8
9
10
11
12
13
template <typename K, typename V>
class Entry { 
public: 
	Entry(const K& k = K(), const V& v = V()) 
		: _key(k), _value(v) { }
	const K& key() { return _key; } 
	const V& value() { return _value; } 
	void setKey(const K& k) { _key = k; } 
	void setValue(const V& v) { _value = v; } 
private: 
	K _key; 
	V _value; 
};


So I have a vector declared like so,

 
std::vector<Entry> list;


My question is, is there a way to declare an iterator for this using the vector stl? I have tried declaring it like so,

 
std::vector<Entry>::iterator it = list.begin();


But I receive this error: Error C7510 'iterator': use of dependent type name must be prefixed with 'typename'

I am not sure how to declare it, or if there even is a way to declare it since I am using my own object. I am trying to access the key value pairs which is why I am trying to create an iterator. Is there away to do this? Or will I have to create my own iterator?
Last edited on
I'm surprised the compiler made it as far as you claim it did.

Template arguments must identify a type, but Entry identifies a class template, not a type.

Please show a complete program that exhibits the problem.
I am trying to create a class that implements various sorting algorithms, I have to read in a file and make a list of key value pairs, where one value will be an integer and the other is going to be a string of that same integer value, I am not sure if how I am inserting them into my vector is correct, but I am just trying to find a way to read the key values from my vector first, which is why I am trying to use an iterator.

Here is the class so far,
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
template <typename K, typename V>
class Sorting {
public:
	typedef Entry<K, V> Entry;
	Sorting(std::string file) {
		std::ifstream entryFile;
		entryFile.open(file);
		if (entryFile.fail())
		{
			std::cout << "Error: File not found\n";
			std::cout << "Press enter key to exit...\n";
			std::getchar();
			exit(1);
		}
		K kValue;
		V vValue;
		while (entryFile >> kValue)
		{
			list.push_back(Entry(kValue, vValue));
		}
		entryFile.close();
	};

	void printList() {
		std::vector<Entry>::iterator it = list.begin();
		for (it; it != list.end(); it++)
			std::cout << (*it).value() << " " << (*it).key << " ";
	}
private:
	std::vector<Entry> list;
};


Update:
I was able to figure it out.

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
template <typename K, typename V>
class Sorting {
public: 
	typedef Entry<K, V> Entry;
	typedef std::vector<Entry> List;
	typedef typename List::iterator it;
public:
	Sorting(std::string file) { 
		std::ifstream entryFile;
		entryFile.open(file);
		if (entryFile.fail())
		{
			std::cout << "Error: File not found\n";
			std::cout << "Press enter key to exit...\n";
			std::getchar();
			exit(1);
		}
		K kValue;
		V vValue;
		while (entryFile >> kValue)
		{

			list.push_back(Entry(kValue, vValue));
		}
		entryFile.close();
	}

	void printList() {
		std::cout << "List is: ";
		it p = list.begin();
		for (p; p != list.end(); p++)
			std::cout << (*p).key() << " " << (*p).value() << " ";
		std::cout << "\n";
	}

private: 
	List list;
};


But now I am having trouble with entering in both the key value pairs in my while loop. For my assignment, I have to read in a file with numbers and I have to insert that number into a key value pair where the key is an int of that number and the value is a string of that same number. However, since I am using templates, there is no way to convert it from what I save the value into when reading the file, in my case kValue. Is there a way to read in the number and save it to both kValue and vValue at the same time?

I was able to do it very inefficiently by inserting them into vectors of kValues and vValues, going through the file once for each vector then looping through the values and pushing them into my list. So I read the file 2 times, and then looped through them all again once more to insert them into my list... This is extremely inefficient, so I am hoping there is a way to read in and save them at the same time...

This is how I did it to make it more clear,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
entryFile.open(file);
K kValue;
V vValue;
std::vector<K> kValues;
std::vector<V> vValues;
while (entryFile >> kValue)
	kValues.push_back(kValue);
entryFile.close();
entryFile.open(file);
while (entryFile >> vValue)
	vValues.push_back(vValue);
for (int i = 0; i < kValues.size(); i++)
	list.push_back(Entry(kValues.at(i), vValues.at(i)));
entryFile.close();
Last edited on
1
2
3
4
5
template <typename K, typename V>
class Sorting {
public: 
	typedef Entry<K, V> Entry;
       // ... 
That's horrendous. It's also ill-formed NDR:

A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.

http://eel.is/c++draft/basic.scope.class#2

(It also would have been necessary information to address the first question you posed.)

To correct this issue, use different name for the typedef, or eliminate it entirely.
Last edited on
Okay, I decided to just rename it E

1
2
3
4
5
6
template <typename K, typename V>
class Sorting {
public: 
	typedef Entry<K, V> E;
	typedef std::vector<E> List;
	typedef typename List::iterator it;
For my assignment, I have to read in a file with numbers and I have to insert that number into a key value pair where the key is an int of that number and the value is a string of that same number.

std::pair<int, std::string> ?
Anyway, if the ‘key’ is an int, usually a std::vector<std::string> can do the trick, if you consider the element position as a key.


But now I am having trouble with entering in both the key value pairs in my while loop.
1
2
3
4
5
6
7
K kValue;
V vValue;
while (entryFile >> kValue)
{

    list.push_back(Entry(kValue, vValue));
}

Do read both the values:
 
while (entryFile >> kValue >> vValue)


Okay, I decided to just rename it E

Does that solved your problems?
I think you’re making your life pointlessly hard.

This is what I had to do to make your code work (I don’t guarantee it’s correct):
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//#include <cstdio>
//#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>


#ifndef ENTRY_HPP
#define ENTRY_HPP


template <typename K, typename V>
class Entry {
public:
    Entry( const K& = {}, const V& = {} );
    const K& getKey() const;
    const V& getValue() const;
    void setKey( const K& );
    void setValue( const V& );

private:
    K key;
    V value;
};


#endif // !ENTRY_HPP


template<typename K, typename V>
Entry<K, V>::Entry( const K& k, const V& v )
    : key ( k )
    , value { v }
{
}


template<typename K, typename V>
const K& Entry<K, V>::getKey() const
{
    return key;
}


template<typename K, typename V>
const V& Entry<K, V>::getValue() const
{
    return value;
}


template<typename K, typename V>
void Entry<K, V>::setKey( const K& k )
{
    key = k;
}


template<typename K, typename V>
void Entry<K, V>::setValue( const V& v )
{
    value = v;
}


#ifndef SORTING_HPP
#define SORTING_HPP


template <typename K, typename V>
class Sorting {
public:
    using MyEntry = Entry<K, V>;
    using MyList = std::vector<MyEntry>;
    using it = typename MyList::iterator;
    using const_it = typename MyList::const_iterator;

//    Sorting( std::string file );
    Sorting( std::istringstream& );

    it begin();
    const_it cbegin() const;
    it end();
    const_it cend() const;
    void printList() const;

private:
    MyList mylist;
};


#endif // !SORTING_HPP


template<typename K, typename V>
//Sorting<K, V>::Sorting( std::string file )
Sorting<K, V>::Sorting( std::istringstream& file )
{
//    std::ifstream entry_file( file );
//    if (!entry_file) {
//        std::cout << "Error: File not found\nPress enter key to exit...\n";
//        std::getchar();
//        std::exit( 1 );       // FIXME: improve this
//    }
    K k_value;
    V v_value;
//    while (entry_file >> k_value >> v_value) {
    while (file >> k_value >> v_value) {
        mylist.push_back( MyEntry( k_value, v_value ) );
    }
}


template<typename K, typename V>
typename Sorting<K, V>::it Sorting<K, V>::begin()
{
    return mylist.begin();
}


template<typename K, typename V>
typename Sorting<K, V>::const_it Sorting<K, V>::cbegin() const
{
    return mylist.cbegin();
}


template<typename K, typename V>
typename Sorting<K, V>::it Sorting<K, V>::end()
{
    return mylist.end();
}


template<typename K, typename V>
typename Sorting<K, V>::const_it Sorting<K, V>::cend() const
{
    return mylist.cend();
}


template<typename K, typename V>
void Sorting<K, V>::printList() const
{
    std::cout << "List is:\n";
    for ( const_it p { cbegin() }; p != mylist.cend(); ++p ) {
        std::cout << p->getKey() << ' ' << p->getValue() << '\n';
    }
    std::cout << '\n';
}


int main()
{
    std::istringstream iss {
        "Jorge  626"
        "Jorge2 627"
        "Jorge3 628"
        "Jorge4 629"
    };
    Sorting<std::string, int> s( iss );
    s.printList();
}


Output:
List is:
Jorge 626
Jorge2 627
Jorge3 628
Jorge4 629


Do you really prefer all this mess to a plain old faithful std::vector<std::string>?

Or are you required to implement the equivalent of a std::map, instead?
@Enoizat
Unfortunately, the txt file I had to read in from was a list of numbers with 12 columns separated by spaces. So something like this,

......
939 1639 1875 2095 1467 5047 2275 6911 2763 7 5491 5327
731 6999 7427 1439 7659 5543 3987 7535 3067 7927 7459 3135
......

My key and value for each entry has to be the same number. So for example my key has to be an int value of 939, and value has to be a string "939".

So using

 
while (entryFile >> kValue >> vValue)

Wasn't working for me, as it would store the two different numbers.

I honestly do not prefer this mess, but it's what was asked for in my assignment. The reasoning (I believe) was because my professor wanted us to keep track of data from different sorting algorithms such as runtime, key comparisons, and data moves. He wanted us to to compare the data of how these algorithms performed when using int vs strings. Which I don't know why we couldn't just create a vector for string and int separately. We did not even have to do anything with the values portion and it had nothing to do with std::map.

Nevertheless, I just decided to keep it the way I had it. Thank you for your help and suggestions though! It was really greatly appreciated.

Quick questions if you can help with code etiquette/convention, is it usually recommended/better to declare functions in your classes and then define them after as you did? I typically just write all my code for the functions inside my classes. Also, what is

1
2
3
4
#ifndef
#define 
...
#endif  


typically used for? I know that it stands for "if not defined" "define" "end if", but what does 'defining' a class or anything for that matter really do and what are its advantages? I usually just create a separate .h file of the class and then '#include' it in whatever file I need it for. Usually keeping most of my #includes in one .h file and then just including that .h file in my main.cpp file. Is this not good practice? Does it achieve the same things as "ifndef" "def" "end if"?
Last edited on
Topic archived. No new replies allowed.