Boost tuple and Vector problem

Hi everyone!

I'm doing a test to try and improve my understanding of vectors and boost tuples and am having the following problem.

I have simplified the issue down to the code pasted below and am working with:
- MS Visual C++ 2008
- Boost library 1.38

Aim
- I want to create a vector of tuple<int, double> elements and pass it by reference to a method/template to populate it.

At the moment in the populate method I can create the tuple element and insert it into a vector also created in the method, but I cannot insert the tuple into the vector which has been passed to the method by reference.

Notes

- I cannot change any of the code in main(), I can only write code in the populateData method.
- Not other fancy libraries etc

Error

- The error occurs in the tuple_basic.hpp and I have included it below (cut the length of it but important info is there)

Any help or info would be appreciated!!

Thanks!!!

Code Start===============================================================
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

#include "stdafx.h"
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
#include <numeric>


#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>


template <typename CONTAINER>
void populateData(CONTAINER& container, size_t count)
{

	typedef boost::tuple<int, double> row1_t;

	std::vector<row1_t> myVect;

	for(size_t i=0 ; i<count ; i++)
	{
		intTuple tempTuple((int(i)));
		myVect.push_back(tempTuple);
	
		row1_t myTuple((int(i)), (double(i))/10);

		myVect.push_back(myTuple);	//This works!
		container.push_back(myTuple);	//THIS IS THE PROBLEM LINE
	};
};


int main()	
{
	typedef boost::tuple<int, double>	row1_t;
	typedef std::vector<row1_t>						vec1_t;
	vec1_t vec1;
	populateData(vec1, 100);
	TEST_REQUIRE_EQUAL(vec1.size(), 100);
	TEST_CHECK_EQUAL_AS_STR(vec1[1],"(1 0.1)");
	TEST_CHECK_EQUAL_AS_STR(vec1[99],"(99 9.9)");


}

Code End================================================================


Full Error:

1>------ Build started: Project: wintonExpertTest, Configuration: Debug Win32 ------
1>Compiling...
1>wintonExpertTest.cpp
1>c:\program files\boost\boost_1_38\boost\tuple\detail\tuple_basic.hpp(373) : error C2039: 'tail' : is not a member of 'boost::tuples::cons<HT,TT>'
1> with
1> [
1> HT=double,
1> TT=boost::tuples::detail::map_tuple_to_cons<boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>::type
1> ]
1> c:\program files\boost\boost_1_38\boost\tuple\detail\tuple_basic.hpp(373) : see reference to function template instantiation 'boost::tuples::cons<HT,TT>::cons<T0,boost::tuples::detail::map_tuple_to_cons<boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>::type>(const boost::tuples::cons<HT,boost::tuples::detail::map_tuple_to_cons<boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>::type> &)' being compiled
1> with
1> [
1> HT=double,
1> TT=boost::tuples::cons<double,boost::tuples::detail::map_tuple_to_cons<boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>::type>,
1> T0=double
1> ]
1> c:\program files\boost\boost_1_38\boost\tuple\detail\tuple_basic.hpp(626) : see reference to function template instantiation 'boost::tuples::cons<HT,TT>::cons<T0,boost::tuples::cons<double,boost::tuples::detail::map_tuple_to_cons<boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>::type>>(const boost::tuples::cons<HT,boost::tuples::cons<double,boost::tuples::detail::map_tuple_to_cons<boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>::type>> &)' being compiled
Compiles fine for me. Using Boost 1.35.
hmm interesting, here is the full code that I am actually compiling (I tried to simplify the code above to make the problem easier to understand...:( )

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
 #include "stdafx.h"
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
#include <numeric>


#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>

static bool testFailure(false);
static size_t testCount(0);



#define TEST_REQUIRE_EQUAL(a, b)													\
{																					\
	++testCount;																	\
	if (a != b) {																	\
		std::cout << "ERROR: TEST ABORTING (" #a " != " #b ")" << std::endl;		\
		exit(1);																	\
	}																				\
}

#define TEST_CHECK_EQUAL(a, b)														\
{																					\
	++testCount;																	\
	if (a != b) {																	\
		std::cout << "ERROR: TEST FAILURE (" #a " != " #b ")" << std::endl;			\
		testFailure=true;															\
	}																				\
}

#define TEST_CHECK_EQUAL_AS_STR(a, b)												\
{																					\
	++testCount;																	\
	std::stringstream lhs, rhs;														\
	lhs << a;																		\
	rhs << b;																		\
	if (lhs.str() != rhs.str()) {													\
		std::cout << "ERROR: TEST FAILURE ("										\
			<< lhs.str()															\
			<< " != "																\
			<< rhs.str()															\
			<< ")"																	\
			<< std::endl															\
		;																			\
		testFailure=true;															\
	}																				\
}





template <typename CONTAINER>
void populateData(CONTAINER& container, size_t count)
{

	typedef boost::tuple<int, double> row1_t;

	std::vector<row1_t> intDoubTupleVect;

	for(size_t i=0 ; i<count ; i++)
	{
	
		row1_t anIntDoubTuple((int(i)), (double(i))/10);
		intDoubTupleVect.push_back(anIntDoubTuple);
		container.push_back(anIntDoubTuple);	//This is causing problems
	};

}




template<typename ITERATOR_TYPE>
typename ITERATOR_TYPE::value_type sum(const ITERATOR_TYPE& first, const ITERATOR_TYPE& last)
{
	typedef typename ITERATOR_TYPE::value_type value_type;
	value_type count(static_cast<value_type>(std::distance(first,last)));
	if(count==0)
		throw std::exception("Cannot calculate the sum of empty series.");
	return std::accumulate(first, last, value_type(), std::plus<value_type>());
}


template<typename ITERATOR_TYPE>
typename ITERATOR_TYPE::value_type mean(const ITERATOR_TYPE& first, const ITERATOR_TYPE& last)
{
	typedef typename ITERATOR_TYPE::value_type value_type;
	value_type count(static_cast<value_type>(std::distance(first,last)));
	return sum(first, last)/count;
}

template<typename CONTAINER> 
typename CONTAINER::value_type mean(const CONTAINER& container)							
{
	return mean(container.begin(), container.end());
}


int main()	
{
	// challenge 1 - pass the following tests
	typedef boost::tuple<int, double>				row1_t;
	typedef std::vector<row1_t>						vec1_t;
	vec1_t vec1;
	populateData(vec1, 100);
	TEST_REQUIRE_EQUAL(vec1.size(), 100);
	TEST_CHECK_EQUAL_AS_STR(vec1[1],"(1 0.1)");
	TEST_CHECK_EQUAL_AS_STR(vec1[99],"(99 9.9)");


	typedef boost::tuple<int, double, double>		row2_t;
	typedef std::vector<row2_t>						vec2_t;
	vec2_t vec2;
	populateData(vec2, 100);
	TEST_REQUIRE_EQUAL(vec2.size(), 100);
	TEST_CHECK_EQUAL_AS_STR(vec2[1],"(1 0.1 0.01)");
	TEST_CHECK_EQUAL_AS_STR(vec2[99],"(99 9.9 0.99)");


	// challenge 2 - create a specialisation for strings
//	typedef boost::tuple<int, double, std::string>	row3_t;
//	typedef std::vector<row3_t>						vec3_t;
//	vec3_t vec3;
//	populateData(vec3, 100);
//	TEST_REQUIRE_EQUAL(vec3.size(), 100);
//	TEST_CHECK_EQUAL_AS_STR(vec3[1],"(1 0.1 1/100)");
//	TEST_CHECK_EQUAL_AS_STR(vec3[99],"(99 9.9 99/100)");

	// challenge 3 - create a generalised view on the series - ideal solution should not copy data
	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<0>(vec1)), 49);
	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<1>(vec1)), 4.95);

	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<0>(vec2)), 49);
	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<1>(vec2)), 4.95);
	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<2>(vec2)), 0.495);

	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<0>(vec3)), 49);
	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<1>(vec3)), 4.95);

	TEST_CHECK_EQUAL_AS_STR(testCount, 17);
	if (!testFailure) {
		std::cout << "Congratulations!\n";
	}

}



 
On line 61, you're assuming an std::vector<boost::tuple<int,double> > will be passed, while you pass an std::vector<boost::tuple<int,double,double> > on line 119.
Agreed helios...

I'm just trying to get things going... I know it won't work for the second part of the problem so I'm trying to work around, try some things out and learn enough to be able to solve the problem properly...

Any ideas on how it should be approached to that it works when I reach line 119?

Thanks for the comment though! :)
1
2
template <typename T>
void populateData(std::vector<T> &container, size_t count)

Although I don't know how you'll construct the temporary object in the loop.
the function was already given as:

template <typename CONTAINER>
void populateData(CONTAINER& container, size_t count)
{
}


So I don't think I can change it...
In that case, here's a hint: CONTAINER::value_type
Last edited on
Firstly, thanks for everyone's help so far! So here's my code now.

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 "stdafx.h"
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
#include <numeric>

#include <boost/lexical_cast.hpp>	//MR Added to cast from double to string

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>


static bool testFailure(false);
static size_t testCount(0);


#define TEST_REQUIRE_EQUAL(a, b)													\
{																					\
	++testCount;																	\
	if (a != b) {																	\
		std::cout << "ERROR: TEST ABORTING (" #a " != " #b ")" << std::endl;		\
		exit(1);																	\
	}																				\
}

#define TEST_CHECK_EQUAL(a, b)														\
{																					\
	++testCount;																	\
	if (a != b) {																	\
		std::cout << "ERROR: TEST FAILURE (" #a " != " #b ")" << std::endl;			\
		testFailure=true;															\
	}																				\
}

#define TEST_CHECK_EQUAL_AS_STR(a, b)												\
{																					\
	++testCount;																	\
	std::stringstream lhs, rhs;														\
	lhs << a;																		\
	rhs << b;																		\
	if (lhs.str() != rhs.str()) {													\
		std::cout << "ERROR: TEST FAILURE ("										\
			<< lhs.str()															\
			<< " != "																\
			<< rhs.str()															\
			<< ")"																	\
			<< std::endl															\
		;																			\
		testFailure=true;															\
	}																				\
}

//Function for challenge 1, for when recursion hits last tuple element
inline void set_to_val_over_ten(const boost::tuples::null_type&, double){};

//Challenge 1 - populates tuple recursively
template<typename H, typename T>
inline void set_to_val_over_ten(boost::tuples::cons<H, T>& x, double V )
{
	x.get_head() = V;
	set_to_val_over_ten(x.get_tail(), V/10);
}

//Challenge 2 - specialisation for strings
template< typename T>
inline void set_to_val_over_ten(boost::tuples::cons<std::string, T>& x, double V )
{

	x.get_head() = boost::lexical_cast<std::string>(V);
	set_to_val_over_ten(x.get_tail(), V/10);
}

//Challenge 1 - Provided function template
template <typename CONTAINER>
void populateData(CONTAINER& container, size_t count)
{
	for(size_t i=0 ; i<count ; i++)
	{
		typename CONTAINER::value_type tupleToAdd(i);
		set_to_val_over_ten(tupleToAdd.get_tail(), double(i)/10.0);
		container.push_back(tupleToAdd);	
	};
}




template<typename ITERATOR_TYPE>
typename ITERATOR_TYPE::value_type sum(const ITERATOR_TYPE& first, const ITERATOR_TYPE& last)
{
	typedef typename ITERATOR_TYPE::value_type value_type;
	value_type count(static_cast<value_type>(std::distance(first,last)));
	if(count==0)
		throw std::exception("Cannot calculate the sum of empty series.");
	return std::accumulate(first, last, value_type(), std::plus<value_type>());
}


template<typename ITERATOR_TYPE>
typename ITERATOR_TYPE::value_type mean(const ITERATOR_TYPE& first, const ITERATOR_TYPE& last)
{
	typedef typename ITERATOR_TYPE::value_type value_type;
	value_type count(static_cast<value_type>(std::distance(first,last)));
	return sum(first, last)/count;
}

template<typename CONTAINER> 
typename CONTAINER::value_type mean(const CONTAINER& container)							
{
	return mean(container.begin(), container.end());
}


int main()	
{
	// challenge 1 - pass the following tests
	typedef boost::tuple<int, double>				row1_t;
	typedef std::vector<row1_t>						vec1_t;
	vec1_t vec1;
	populateData(vec1, 100);
	TEST_REQUIRE_EQUAL(vec1.size(), 100);
	TEST_CHECK_EQUAL_AS_STR(vec1[1],"(1 0.1)");
	TEST_CHECK_EQUAL_AS_STR(vec1[99],"(99 9.9)");


	typedef boost::tuple<int, double, double>		row2_t;
	typedef std::vector<row2_t>						vec2_t;
	vec2_t vec2;
	populateData(vec2, 100);
	TEST_REQUIRE_EQUAL(vec2.size(), 100);
	TEST_CHECK_EQUAL_AS_STR(vec2[1],"(1 0.1 0.01)");
	TEST_CHECK_EQUAL_AS_STR(vec2[99],"(99 9.9 0.99)");


	// challenge 2 - create a specialisation for strings
	typedef boost::tuple<int, double, std::string>	row3_t;
	typedef std::vector<row3_t>						vec3_t;
	vec3_t vec3;
	populateData(vec3, 100);
	TEST_REQUIRE_EQUAL(vec3.size(), 100);
	TEST_CHECK_EQUAL_AS_STR(vec3[1],"(1 0.1 1/100)");
	TEST_CHECK_EQUAL_AS_STR(vec3[99],"(99 9.9 99/100)");

	// challenge 3 - create a generalised view on the series - ideal solution should not copy data
	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<0>(vec1)), 49);
	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<1>(vec1)), 4.95);

	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<0>(vec2)), 49);
	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<1>(vec2)), 4.95);
	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<2>(vec2)), 0.495);

	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<0>(vec3)), 49);
	//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<1>(vec3)), 4.95);

	TEST_CHECK_EQUAL_AS_STR(testCount, 17);
	if (!testFailure) {
		std::cout << "Congratulations!\n";
	}

}





The problem I'm now having is when main() calls the following line in challenge 2

TEST_CHECK_EQUAL_AS_STR(vec3[1],"(1 0.1 1/100)");

I've made the mistake of just changing the double to a string instead of a fraction such as "1/100" by using the boost lexical cast.

While I could change the template function to unclude the vector element number currently being iterated
(In the above case this would give the numerator) and also pass in the tuple element number being
iterated through (10^ this number would give the denominator).

I'm fairly sure there must be a more elegant way of doing this?

Any ideas please? :)

Topic archived. No new replies allowed.