C4244 With templates

Started by
7 comments, last by Fruny 19 years, 1 month ago
Still working on learning STL, I started working on a simple midrange function. It works correctly, but I get 2 C4244 warnings when I compile. testie2.cpp(27) : warning C4244: '=' : conversion from 'std::allocator<_Ty>::value_type' to 'float', possible loss of data with [ _Ty=int ] testie2.cpp(67) : see reference to function template instantiation 'T Midrange<float,std::vector<_Ty>::iterator>(FwItr,FwItr)' being compiled with [ T=float, _Ty=int, FwItr=std::vector<int>::iterator ] testie2.cpp(29) : warning C4244: '=' : conversion from 'std::allocator<_Ty>::value_type' to 'float', possible loss of data with [ _Ty=int ] Here is the function:

template <typename T, typename FwItr>
T	Midrange( FwItr b, FwItr e )
{
	T	min = T(*b);
	T	max = T(*b);

	for(; b != e; ++b)
	{
		if( *b > max )
			max = *b;  // line 27: C4244
		if( *b < min )
			min = *b;  // line 29: C4244
	}
	return ( min + max ) / 2;
}

// V
vector<int>		V;

// line 67: reference
cout << "Float Midrange:  " << Midrange<float>(V.begin(), V.end()) << endl;





It does correctly convert to a float, because the result sometimes ends with point five. So should I live with the warnings becase it still works? I am pretty sure there is a way to get these cleaned up. I do not get the warnings when I use a vector<float> F with Midrange<float>(...).
Advertisement
I would say
#include <iterator>template <typename T, typename FwItr>T Midrange( FwItr b, FwItr e ){	typedef typename std::iterator_traits<FwItr>::value_type value_type;	value_type min(*b), max(*b);	for(; b != e; ++b)	{		if( *b > max )			max = *b;		else if( *b < min )			min = *b;	}	return T(min + max) / 2;}


since that get's rid of conversions and only converts the final return value (if needed).

Else everytime you assign max or min you would get a conversion, that's what your original warnings were telling you.

hope that helps :)
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
That did take care of the warnings. So value_type is more generic then T, but still serves the same function? I don't understand why I was able to do T sum = T(); sum += *b; prevoiusly, but now I cant do something which seems very similar in code.

I guess this is where I ask for a reference to a site explaining the use of iterator_traits, or maybe a good introduction to STL book.

I have read over the sgi STL page, there does not seem to be alot of obvious places to pickup info on STL. I would like to know the 'whys' of what I am doing.

And thank you again DigitalDelusion.
I would recomend the book "The C++ Standard Library A Tutorial and Reference" by Nicolai Josuttis it's an excellent refrence.

As for your questions:

the thing here is that T and value_type might be diffrent types, basicly iterator_traits is a way to query the iterator for information value_type is simply the type that the iterator yields on dereferencing.

When you request a diffrent restult type (T) than the value_type you would need a conversion and that's where the warnings came from.

Hope that clearifys things a bit.
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
Quote:Original post by mozie
That did take care of the warnings. So value_type is more generic then T, but still serves the same function? I don't understand why I was able to do T sum = T(); sum += *b; prevoiusly, but now I cant do something which seems very similar in code.


You could use T directly before because your function parameter type (vector<T>) did let the compiler figure out what T was. With iterators, you don't have the container type anymore. So, to get at the type of the variable the iterator points to, you go through the iterator_traits class template.

Quote:I guess this is where I ask for a reference to a site explaining the use of iterator_traits, or maybe a good introduction to STL book.


Just like the numeric_limits<T> class template does provide information on a numeric type T (min value, max value, number of digits, precision, etc), the iterator_traits<T> class template does provide information on an iterator type (including pointers, which is why the information is not just provided as iterator class members). They give you information on the type the iterator points to, on the type of the difference of two iterators (it1-it2), and the category of iterator (random access, forward, bidirectional...) which defines the operations available on the iterator (you can do it += 10 on a random access iterator like vector's but not on a list iterator, which is only bidirectional; if you had a singly-linked list, you wouldn't be able to decrement the iterator, so it would only be a forward iterator).

Iterator categories do matter when implementing generic algorithms, as you'll want to rely on the most generic iterator category that does enable you to implement you algorithm efficiently. Some algorithms are implemented to detect the type of iterator passed to them - template magic you'll get to learn if you keep developing your own generic algorithms development (yeah, you're doing more than just learning the STL as most people see it [grin]).

Quote:I have read over the sgi STL page, there does not seem to be alot of obvious places to pickup info on STL. I would like to know the 'whys' of what I am doing.


Nicolai Josuttis' book is a must-have.
"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
Quote:Original post by Fruny
template magic you'll get to learn if you keep developing your own generic algorithms development (yeah, you're doing more than just learning the STL as most people see it [grin]).


Are you saying that I should not be trying to learn STL by trying to do these generic algorithms? I thought that they would be a good way for me to lean how to use STL, insted of just how the syntax works.

Also, the book "The C++ Standard Library" was published in 1999. I understand that STL is still somewhat new, I assume that the only things that would have changed from when the book was written to now, would be things inside the compiler, not any of the syntax or functions.

Next up is going to be a Mode function I think, which I will definatly need guidance with.

Thanks for all the help!
Quote:Original post by mozie
Next up is going to be a Mode function I think, which I will definatly need guidance with.


I have a better exercise (if your interested) before you continue your journey of implementating generic routines [smile].

1. Learn every single detail about templates, quite importantly template partial specializations.

2. Understand what are *Concepts* (in standard C++ context in particular), for e.g. Random Access Iterator, Sequence, Associative Container, Binary Predicate, Default Constructable.

3. Learn what traits are (iterator, type, character etc) and policy classes, how they work, and the differences between the two (they are very simillar).

4. Once you know that go onto learn how to do Tag & Type dispatching at compile time, where you can select the most optimized method depending on type for a generic routine.

5. How you to implement lazy (e.g. via expression templates) and partial evaluation. (Maybe this should be 6 instead [grin])

6. starting to feel adventurous? start looking into template metaprogramming and generative aswell as generic programming paradigm. How you can use in conjunction with OO. for example with one generative & generic component could generate an entire interface hierarchy while another can generate an entire implementation hierarchy for thoses interfaces. Another example a container of types [smile] yes, sets, vectors, trees etc of types and algorithms for them that work in the land of compile time.

I recommend starting your trail on boost's Generic Programming Techniques page.

EDIT: maybe some of that is going to far [rolleyes]

[Edited by - snk_kid on April 1, 2005 9:09:19 AM]
Quote:Original post by snk_kid
I have a better exercise (if your interested) before you continue your journey of implementating generic routines [smile].

1. Learn every single detail about templates, quite importantly template partial specializations.

I recommend starting your trail on boost's Generic Programming Techniques page.

EDIT: maybe some of that is going to far [rolleyes]


Thanks, awesome! I read over the Generic Programming page there, and then wanted some more info on the template partial specializations. I found a link at cplusplus.com about templates. I cant really comment on the quality of that site, because I am new to the subject and dont know about the level of conent that should be covered. Any other good references for templates anone that people use.. searches gd articles.. I will see if Getting Started with Templates has anything to add.

Here is my usual beginner-level code sample:
template <class T>class Trouble{	T	data;public:	Trouble(T d) { data=d; }	T	get() { return data; }};template <>class Trouble <int>{	int	data;public:	Trouble(int d) { data=d; }	Trouble() { data = 1; }	int	get();};//template <>  /* C2910 */int	Trouble<int>::get(){	return data + 12;}..	Trouble<float>	cTf( 1.2f );	Trouble<int>	cT;	vector<Trouble<int> > VcT (12);	cout << VcT.size() << endl;	cout << cT.get() << endl;	cout << cTf.get() << endl;


and... I am not really clear on this.. template <typename T> and template <class T> are exactly the same?

[Edited by - mozie on April 1, 2005 8:38:17 PM]
Quote:Original post by mozie
and... I am not really clear on this.. template <typename T> and template <class T> are exactly the same?


In template parameter lists, typename and class play exactly the same role, with one single exception: template template parameters. If you declare T to itself be a template, then the keyword must be class (because it has the format of a class template declaration):

template< template<typename Element, typename Allocator> class Container > class foo { ... };foo<vector> bar; // note vector and not vector<whatever>.


And of course, the typename also plays a role when dealing with dependent names, just like class has a role of its own.
"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

This topic is closed to new replies.

Advertisement