Skip to main content
GameDev.net gamedev.net
🔒 Locked

My first STL + template

Started by mozie Mar 29, 2005 at 7:39 PM 10 replies 1.7k views
Original Post
mozie
mozie
After reading the STL and newbies I realized I should get on it. So I just got home, and after about 20 mins total I created this:

// testie2.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

using namespace std;

template <typename T>
T	Mean( vector<T> t )
{
	// set result to 0
	T re = 0;

	// cast and set the size
	int sz = (int)t.size();

	// loop and sum
	for(size_t i = 0; i < t.size(); ++i)
		re += t;

	// return the sum/size
	return (T)(re / sz);
}

int _tmain(int argc, _TCHAR* argv[])
{
	vector<int>		V;
	vector<float>	F;

	// seed the generator
	srand( (unsigned)time(NULL));

	for(int i = 0; i < 100; ++i)
	{
		// generate a random number
		int rnd = rand() % 1000;
		
		// insert the number
		V.insert(V.begin(), rnd);
		F.insert(F.begin(), (float)rnd);
	}

	// calculate the mean of the numbers
	int	res = Mean<int>(V);
	float	re2 = Mean<float>(F);

	// display results
	cout << res << endl;
	cout << re2 << endl;
	
	system("pause");
	return 0;
}



I had a little trouble with clearing out the type-casting warnings (conversion from 'x' to 'y' possible loss of data), but it works now. I went to the DADS site linked in that prevoius thread, and that is where I got the idea to do the mean. I still want to make templated functions for median, midrange, and mode algorithms too. All-in-all, its a great thread to force you into sucking it up and learning STL. Not a lot of resources came up easily with google, so here is one that helped me with the std::vector stuff. Comments welcome, I just wanted to share my learning experience.
SticksandStones
SticksandStones
Good job! Shame I'm too contempt with reading books on programming than programming to make anything...
Good luck with your future templats, STL, etc!
hippopotomonstrosesquippedaliophobia- the fear of big words
DigitalDelusion
DigitalDelusion
some comments:

Most STL algorithms use pairs of iterators to decouple the algoritm from the actual container it's a usefull ideom.
You're passing the vector by value, that's not good! basicly it means that you copy the whole thing just to send it to your function use a const refrence (refrence to const I guss is the correct terminology) instead.

Casting away typesafty is in most cases the wrong solution, espicially in this case since you could have used size_t instead and got rid of the warnings that way.

Anyhow, good luck with your future endouvers.
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
mozie
mozie
Quote:
Original post by DigitalDelusion
some comments:

Most STL algorithms use pairs of iterators to decouple the algoritm from the actual container it's a usefull ideom.

That was a concern at first, I know I have seen them in other STL for(..) loops. I did not get any errors, and the code worked so I left it be. How should I use the iterators?
Quote:

You're passing the vector by value, that's not good! basicly it means that you copy the whole thing just to send it to your function use a const refrence (refrence to const I guss is the correct terminology) instead.

good catch, I am so bad about that really. I think it is because I do not think of it happening, I just think of it as working.
Quote:

Casting away typesafty is in most cases the wrong solution, espicially in this case since you could have used size_t instead and got rid of the warnings that way.

Anyhow, good luck with your future endouvers.

I did use size_t for 'sz' at first, but I think it gave me another warning on the return line. How should size_t be handled? Is it really good to delcare a var as size_t when it will be used later with another type? If you don't mind explaining a better way.

Thanks!
DigitalDelusion
DigitalDelusion
here's a slightly modified version that gets rid of most of the issues
with your eariler attempt.
template <typename T, typename FwItr>T mean(FwItr b, FwItr e){	T sum = T(), cnt = T();	for(; b != e; ++b, cnt = cnt + 1)		sum += *b;	return cnt ? sum / cnt : T();}


usage would look like this
// display resultscout << mean<int>( V.begin(), V.end()) << endl;cout << mean<float>( F.begin(), F.end()) << endl;


note the added flexibility, if you would want a float mean for the int array you simply would change the first line to
cout << mean<float>( V.begin(), V.end()) << endl;
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
mozie
mozie
Wow, that code is a slap in the face. And I do not mean you are insulting me. I love the three uses of T(), it never crossed my mind. Only two questions come up to me, 'for(; b != e; ++b, cnt = cnt + 1') why not '++cnt', the long 'cnt = cnt + 1' seems out of place in that nice block. I have never used a comma in the third 'for()' param, is it something to do with that? And second, so the 'b' and 'e' are just pointers, and thats all that we are really comparing? The 'sum += *b;' makes me think so, along with your prevoius post. :)

edit: tag misuse
DigitalDelusion
DigitalDelusion
cnt = cnt + 1 is because cnt isn't always of integral type but Im hopeing that any type used for the result at least will support adding 1 to it.

'b' and 'e' are iterators, the concept of an iterator is something that works quite much like a pointer it is a conceptual abstraction of a pointer and they exists in many flavours like forward , bidirectional and random access iterators to name but a few. Forawrd iterators can only be stepped forward bidirectional can be stepped both forward and backward and random access acts pretty much like you would expect a plain pointer to :)
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
mozie
mozie
Quote:
Original post by DigitalDelusion
Forawrd iterators can only be stepped forward bidirectional can be stepped both forward and backward and random access acts pretty much like you would expect a plain pointer to :)


So thats why it was named 'FwItr'. Thanks. :)
Fruny
Fruny
Quote:
Original post by DigitalDelusion
cnt = cnt + 1 is because cnt isn't always of integral type but Im hopeing that any type used for the result at least will support adding 1 to it


Actually, cnt should indeed be of type size_t not of type T. Or, if you're worried about warnings, the int mozie used was OK for most cases.

Also, mozie, there was a rather important inefficiency in your original code (which using iterators does avoid), in that you were passing the vector by value, thus making a copy of all the values it contains (ouch). Passing by constant reference would have eliminated the problem:

template T Mean(const vector& t)

Furthermore, on a compliant compiler, you should be able to do Mean(V) without specifying 'float' or 'int', and the compiler will figure things out automatically from the type of V.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
snk_kid
snk_kid
Quote:
Original post by DigitalDelusion
here's a slightly modified version that gets rid of most of the issues
with your eariler attempt.
*** Source Snippet Removed ***

usage would look like this
// display resultscout << mean<int>( V.begin(), V.end()) << endl;cout << mean<float>( F.begin(), F.end()) << endl;


note the added flexibility, if you would want a float mean for the int array you simply would change the first line to
cout << mean<float>( V.begin(), V.end()) << endl;


Good try but your code is not very generic [smile], here is a version that requires no need to give explicit types (takes advantage of iterator traits & auto type deduction courtesy of the compiler) and reuse exisiting algorithms:

#include <numeric>  // accumlate#include <iterator> // iterator_traits#include <iostream>template < typename InputIterator >typename std::iterator_traits<InputIterator>::value_typemean(InputIterator first, InputIterator last) {    typedef typename std::iterator_traits<InputIterator>::difference_type difference_type;    const difference_type N = std::distance(first, last);    return std::accumulate(first, last, 0) / (N ? N : 1);}int main() {  int A[] = { 1, 2, 3, 4, 5 };  const int N = sizeof(A) / sizeof(int);  std::cout << "mean value: " << mean(A, A + N) << std::endl;  }


[Edited by - snk_kid on March 30, 2005 10:58:22 AM]
DigitalDelusion
DigitalDelusion
snk_kid: yup I guess that's the proper way to do it :) just hope you didn't give the poor OP a heart attack by posting that in for beginners ;)

also note that you actually lost flexibility by assuming that the value_type would be the desired return format sometimes it's actually beneficial to get a float average from a collection of ints.
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
mozie
mozie
Quote:
Original post by DigitalDelusion
snk_kid: yup I guess that's the proper way to do it :) just hope you didn't give the poor OP a heart attack by posting that in for beginners ;)


I have a strong heart, but my jaw is a little loose now that it has hit the floor.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.