Gah, problems >.<

Pages: 12
Hello guys,

So I am writing a couple functions to print to console, the first one prints single data, the second one prints arrays of data. For some reason the second function (overloaded print) takes in and prints out char arrays like it is supposed to, but I can't seem to get it to do the same thing for any other data types. Any ideas why this might be happening? I've been racking my brain and I'm just not sure. I may just end up overloading for each datatype individually if I have to.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
	template <typename DataType>
	void print(DataType output)
	{
		cout << output;
	}
	template <typename DataType>
	void print(DataType output[])
	{
		// local variables
		char seperator = '-'; // Default: space

		for (int i = 0; i < (int(sizeof(output) / sizeof(DataType)) - 1); i++)
		{
			cout << output[i];

			if (i != (int(sizeof(output) / sizeof(DataType)) - 2))
				cout << seperator;
		}
	}


Thanks!
That's because the size of the array is always going to be 4. It's not the size of the array but an individual address for the array's first position. So it's not going to give you the array's length. I kinda forget how you'd go about determining the array's length, sorry.
Char* on the other hand is specialized, in a way, because it is intended to be used as a string-like object. So it prints out all at once.
Ahh, that makes sense. I'll go see what I can find on getting an accurate size.
sizeof(output) / sizeof(DataType) won't work with parameter arrays
You can add the size as template parameter:
1
2
template <typename DataType,unsigned size>
    void print( DataType (&output) [size] ) // 'output' explicitly passed as reference, parentheses make the compiler know that it's not an array of references 

EDIT: oops, it seems that someone has already told you this while I was writing down my answer. Anyway, I left it here...

Maybe it has something to do with the for condition? As far as I know (and I can be wrong, of course) the output parameter is a pointer, so sizeof(output) is size of a pointer (which is normally represented as an int or maybe a long). You can set a log to check this, something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template <typename DataType>
	void print(DataType output)
	{
		cout << output;
	}
	template <typename DataType>
	void print(DataType output[])
	{
		// local variables
		char seperator = '-'; // Default: space

                cout << "sizeof(output) = " << sizeof(output) << "\n";
		for (int i = 0; i < (int(sizeof(output) / sizeof(DataType)) - 1); i++)
		{
			cout << output[i];

			if (i != (int(sizeof(output) / sizeof(DataType)) - 2))
				cout << seperator;
		}
	}

If this is confirmed, you will need to add a second parameter to set the size of the array to print.

1
2
template <typename DataType>
	void print(size_t size, DataType output[])
Last edited on
Bazzy's way is the best way to do it. Pass in the size as a template value. That way you don't have to actually put it in the arguments list. It is determined by the compiler. It is exceptionally reliable and I'd recommend it to the OP. I've seen it somewhere else but I can't remember where..
Just got done running some testing on:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
	template <typename DataType>
	void print(DataType output)
	{
		cout << output;
	}
	template <typename DataType, unsigned size>
	void print(DataType (&output) [size])
	{
		// local variables
		char seperator = '-'; // Default: space

		for (int i = 0; i < size; i++)
		{
			cout << output[i];

			if (i != (size - 1))
				cout << seperator;
		}
	}


So far it works like a charm! Thanks guys for the quick and knowledgeable responses! Thanks a bunch Bazzy, especially for explaining the parenthesis. Always nice to learn something new.
Not sure why you're going to this extent.

 
print( x );


provides nothing more than

 
cout << x;


for any non-array type, and is in fact less useful since it hard-codes to stream to which
to write the data (std::cout),

and

 
print( array );


provides no additional functionality than

1
2
3
4
5
// Somebody please correct my third parameter.  This is OTOMH and I can never remember it
std::copy( array, array + size, ostream_iterator( std::cout, '-' ) ); 

// or using boost::lambda:
std::for_each( array, array + size, std::cout << boost::lambda::_1 << ',' );


and is in fact less useful since it hard-codes to stream to which
to write the data (std::cout).

Boost has a for_each?
It is probably just a mental or practice exercise. There's obviously no real reason to use it.
The third parameter of method #1 should be ostream_iterator<type_of_array>( std::cout, "-" )
No. Can't you see it's in the std namespace?
Last edited on
But then why is the comment boost::lambda?
You can add to namespaces across translation units, so it is possible... and I don't recall a for_each in normal STL.
Of course... I actually forgot about that....
Take notice of line 5 in jsmith's code snippet. boost::lambda is how he could use what appears to be a function body as a parameter to for_each. I just can't seem to wrap my head around how it does that, though! I've even looked at the code for it...
Of course, I know what lambda is. It's for defining one-time conjugate functions without actually giving them names. It's specifically intended to be employed for things such as <algo>, so you don't have to define a whole new function for a specialized purpose; you can instead define a lambda function which has no name. I don't know all the fine points of it but that's essentially how it works.
Most likely, boost::lambda::_1 is an object of type T, and there's an overload for operator<<(std::ostream &,T &) that returns a T2, which is a functor, and also has several overloads. But it's easier to just say it's magical.
I understand there is already methods of doing what I've done so far, but this isn't where it ends, I had to make sure the print part of printing arrays and the text passed worked first. Right now I'm expanding them to take additional optional arguments that change the alignment and offset of the text in the console. I'll post what I have when I'm done.

Also, this is just a simple side project learning C++ befor my college course CSC 111 starts in February. I'm building many small function libraries to make programming redundant code in the course easier. Here is my casing library of functions for anyone to use/edit/distribute as they see fit if anyone can find it useful. I know I will. =)

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
/**
* kccasing.cpp
*	Simple string and character recasing functions.
**
* Author: Kyle Campbell (k.j.campbell@clasnet.sunyocc.edu)
*/

#ifndef KCS_CASING
#define KCS_CASING

#include <string>
using namespace std;

// This file is part of the KC Shared function library.
namespace kcs
{
	/**
	* Function Prototypes
	**
	* lowerCase(c/s): Change the case of the character or an entire string to lower.
	* switchCase(c/s): Switch the case of the character, or each character in a string.
	* upperCase(c/s): Change the case of the character or an entire string to upper.
	**
	* String notes:
	*	Passing an additional argument of true to any of these functions will tell
	*	the function to only manipulate the casing of the first character in the
	*	string.
	*/
	void lowerCase(char& c, bool first_char_only = false);
	void lowerCase(string& s, bool first_char_only = false);
	void switchCase(char& c, bool first_char_only = false);
	void switchCase(string& s, bool first_char_only = false);
	void upperCase(char& c, bool first_char_only = false);
	void upperCase(string& s, bool first_char_only = false);
	
	/**
	* Function Declarations
	*/
	void lowerCase(char& c, bool first_char_only)
	{
		if (c >= 'A' && c <= 'Z')
			c = ((c - 'A') + 'a');
	}
	void lowerCase(string& s, bool first_char_only)
	{
		if (first_char_only)
		{
			lowerCase(s[0]);
			return;
		}
		else
		{
			// Save s.length() in a variable so were not calling it every loop.
			int str_length = int(s.length());
			
			for (int i = 0; i < str_length; i++)
				lowerCase(s[i]);
		}
	}

	void switchCase(char& c, bool first_char_only)
	{
		if (c >= 'a' && c <= 'z')
			c = ((c - 'a') + 'A');
		else if (c >= 'A' && c <= 'Z')
			c = ((c - 'A') + 'a');
	}
	void switchCase(string& s, bool first_char_only)
	{
		if (first_char_only)
		{
			switchCase(s[0]);
			return;
		}
		else
		{
			// Save s.length() in a variable so were not calling it every loop.
			int str_length = int(s.length());
			
			for (int i = 0; i < str_length; i++)
				switchCase(s[i]);
		}
	}

	void upperCase(char& c, bool first_char_only)
	{
		if (c >= 'a' && c <= 'z')
			c = ((c - 'a') + 'A');
	}
	void upperCase(string& s, bool first_char_only)
	{
		if (first_char_only)
		{
			upperCase(s[0]);
			return;
		}
		else
		{
			// Save s.length() in a variable so were not calling it every loop.
			int str_length = int(s.length());
			
			for (int i = 0; i < str_length; i++)
				upperCase(s[i]);
		}
	}
}

#endif 


Also, thanks for the continued input guys, I'll post my final simpio.cpp file once I've finished the output and input functions.

-- Kyle
What the? Half the functions there don't use the second parameter. Also, tolower() and toupper().
=O forgot to remove the second param from the char ones lol. Like I said I'm trying not to use libraries to do the job for me, I'm writing only the functions I know I'll need. Plus the cctype has functions I don't need and the functions it does have don;t do everything I'd like them to do.

I realize I'm a beginner, but I was just posting that library because I use it. I figured it may be useful to some others as well. :\
Pages: 12