Calling member function of a template class recursively - c++

I have a working implementation of a avltree as a template class. I am adding two functions to this working implementation. These two functions that will transverse through the entire tree recursively and preform some calculations.
//avltree.cpp
//see comment in code below
template <class Comparable>
void AvlTree<Comparable>::transverseTree( AvlNode<Comparable> *t, const char *word, char matchingWords[100][MAX_LENGTH + 1], int *count) const
{
int distance;
if( t != NULL )
{
distance = levDistance(t->element/*avl word*/, word);
if (distance == 1)
{
*count++;
strcpy(matchingWords[*count], t->element/*avl word*/);
}
//error is here
transverseTree( t->left, word, matchingWords );
transverseTree( t->right, word, matchingWords );
}
}
//avltree.h
//new function
void transverseTree(AvlNode<Comparable> *t, const char *word, char matchingWords[100][MAX_LENGTH + 1],
int *count) const;
//new function
int levDistance(const char *str1, const char *str2) const;
When I try calling this function recursively, I receive this error message:
AvlTree.cpp:412:31: error: no matching function for call to ‘AvlTree<const char*>::transverseTree(AvlNode<const char*>*&, const char*&, char (*&)[34]) const’
transverseTree( t->left, word, matchingWords );
^
Why are their ampersands on the argument types to the recursive call? Are these references, and if so - how am I doing this?

You forgot to pass count in the recursive calls.
transverseTree( t->left, word, matchingWords, count ); // Missing count
transverseTree( t->right, word, matchingWords, count ); // Missing count

The signature looks like
void
AvlTree<Comparable>::transverseTree(AvlNode<Comparable> *t,
const char *word,
char matchingWords[100][MAX_LENGTH + 1],
int *count)
But your call looks like
transverseTree( t->right, word, matchingWords );
I think you forgot to pass the count pointer.

It probably has to do with your recursive calls not having the correct parameters.
void transverseTree(AvlNode<Comparable> *t, const char *word, char matchingWords[100][MAX_LENGTH + 1], int *count) const;
Here, when you declare this function, it takes in 4 parameters.
However, when you call this function recursively:
transverseTree( t->left, word, matchingWords );
You're forgetting about that last parameter *count, therefore that function you're trying to call is not defined with that particular function signature.

Ampersands don't matter here; they just allow passing an argument as a reference. Still, functions having non-reference arguments of the same type will also match (effectively requiring object copying before the function call) provided that there is a copy constructor defined (either explicitly or by default) for an argument type. In this case, the object type is a pointer, and a copy constructor is implicitly defined for it (merely copying the value). So there is no problem with that.
Still it seems the last argument, count , is missing in the recursive calls. It may be the cause of a compilation error (of course unless your have specified a default value for it in a declaration inside AvlTree class).

Related

How to pass a char as an argument of a function inside a class using template

I'm trying to pass a char array into a function(push) inside this class(BaseStack):
template < class T >
class BaseStack
{
void push(const T&item){
//Ignore
}
}
What I tried was:
char finalstring[L];
for(int i = 0 ; i < 5; i++)
finalstring[i] = 'x';
BaseStack<char> c;
c.push(finalstring);
But my compiler said that I was doing an invalid conversion
BaseStack<char> c;
This means that your template parameter is char. This is what you specified for the template parameter. Therefore, the instance of your template is, in so many words, and very loosely speaking:
class BaseStack
{
void push(const char &item){
//Ignore
}
}
This is what happens, since your template parameter is a char. T is char, and since the parameter in the template is void push(const T &item), then that's what you get.
c.push(finalstring);
finalstring is a char array, which decays to a char *. This attempts to pass a char * to a class method that takes a (const refence to a) char. This is not allowed in C++, and that's the reason for your compilation error.
It is unclear what your intent is here, whether the template parameter should be either a const T *, or you need to pass finalstring's first character, only. Doing either will solve this particular compilation error.

recursive variadic template function call "loses" pointer on second argument type

I've got a function (GetArgs) using a variadic template that sorts through it's arguments (each a pointer), sending each to another function (GetArg) that has been overloaded for each type (at the moment int & float). The overloaded funtions for each type then set the value at the pointer.
It compiles fine, and when I call the function with however many arguments of a single type it runs fine. However if I use the two types (float & int), it will run fine until the first occurrence of the second type, crashing because (from what I can tell) the pointer address is null (0x0 in debugger).
Here are my function definitions(declared in namespace included in main):
namespace.h
int GetArg(int iStackPos,int *i);
int GetArg(int iStackPos,float *f);
template<typename tFirst> int GetArgs(tFirst first)
{
GetArg(-1,first);
}
template<typename tFirst, typename... tRest> int GetArgs(tFirst first, tRest... rest)
{
int iStackPos = ((sizeof...(rest) + 1) * -1);
GetArg(iStackPos,first);
GetArgs((rest)...);
return 0;
}
namespace.cpp
int GetArg(int iStackPos,int *i)
{
*i = 1;
}
int GetArg(int iStackPos,float *f)
{
*f = 2.5;
}
call to get args in main:
would run fine:
int *i1;
float *f1;
namespace::GetArgs(f1,f1,f1,f1); //no use of int
would crash:
int *i1;
float *f1;
namespace::GetArgs(f1,i1,f1); //use of int
The same is true when int comes first and float after.
The null pointer happens in the recursive GetArgs() call, and the crash occurs because the overloaded int GetArg() tries to write to that.
The iStackPos is used as position on lua stack, as this is meant to be a wrapper to get arguments from lua. However I've replaced lua code with just assigning int 1, float 2.5, as the lua code wasn't the issue.
As others already suggested, you're passing uninitialized memory into your function. That produces undefined behavior.
Also, you're not returning anything in the GetArg functions and the first GetArgs. This can get you into trouble as well.
And your combining size_t and int when calculating iStackPos.

Qsort compare function

void qsort (void* base, size_t num, size_t size,
int (*compare)(const void*,const void*));
Why does the qsort function want an int* return type for compare when the compare function is of type int?
int compare (const void * a, const void * b)
{
if ( *(MyType*)a < *(MyType*)b ) return -1;
if ( *(MyType*)a == *(MyType*)b ) return 0;
if ( *(MyType*)a > *(MyType*)b ) return 1;
}
Can someone explain this please, my program wont compile because of this. Thanks!
Code taken from this source:
http://www.cplusplus.com/reference/cstdlib/qsort/
It is not returning an int *, it is returning an int. compare is a function pointer. The * you are seeing there defines it as a function pointer. (Note the parentheses around *compare.)
cdecl parse of int (*compare)(const void*,const void*)):
declare compare as pointer to function (pointer to const void, pointer to const void) returning int
This would be the parameter declaration if it were a pointer to a function returning an int *:
int * (*compare)(const void*,const void*))
If your code is not compiling then it is for some other reason. Consider adding the error message to your question (or creating a new question) if you would like more specific advice about the compiler error.

instantiated from here error with a predicate template function

I tried researching this question already, but it seems as though every question dealing with my error has to do with classes and their default constructors whereas my code contains no classes. It's a simple size() function that returns the number of elements in a given array. (I'm aware there is a built in size() function, that's not the point).
I at first thought that it was upset with my naming my function size() when a size() function already existed so I changed mine to sise() but I still recieve the same error and have no idea how to solve it.
Code:
template<class T > int sise(T array[], int count){
if(array[count+1]== NULL){
return count+1;
}
else{
return sise(array,count+1);
}
}
template <class T> int sise(T array[]){
return sise(array , 0);
}
int main(){
int array[] = {1 , 7 , 5, 4, 6 ,2 , 3};
int len = sise<int>(array);
std::cout << len << std::endl;
//print<int>(array);
// shakersort<int>(array);
// print<int>(array);
return 0;
}
Don't worry about the commented out function calls in main(), as each respective's calls functions have been commented out but the same error of
Shakersort.cpp: In function ‘int sise(T*, int) [with T = int]’:
Shakersort.cpp:60:24: instantiated from ‘int sise(T*) [with T = int]’
Shakersort.cpp:77:28: instantiated from here
Shakersort.cpp:51:3: warning: NULL used in arithmetic [-Wpointer-arith]
is given. What is going on?
The compiler is warning about NULL being compared to an int from the looks of it. Not strictly an error (nor is it made an error) but a likely indication of false assumptions being made. One such assumption seems to be that arrays are magically null-terminated: they are not. That is something very specific to string literals and even then the null-terminator is not NULL but rather '\0'. You'll either need to pass the size of the array along or you'll need to deduce it using a template, e.g.:
template <typename T, int Size>
int sise(T (&array)[Size], int count) {
...
}

Failure to pass pointer to const data as function template argument

I have a function which takes a function pointer as an argument, and then calls that function with its own arguments:
typedef int (*my_func_ptr)( int );
int foo( my_func_ptr f ) {
static int i = 0;
return i = f( i );
}
Sometimes, I need to pass functions to foo that depend on more than just integer input to spit out a result.
int add_strlen( int i, const char* s ) {
return i + strlen( s );
}
I could rework the above code to make use of std::function and then use std::bind, but it is preferable to me that these functions be created at compile time, so I'm using templates.
template<const char* S>
int add_strlen( int i ) {
return i + strlen( S );
}
/**
* Usage:
* char bar[] = "bar";
* foo( add_strlen<bar> );
*/
My problem arises when using pointers as template arguments. Whenever I use a pointer to constant data of any type as a template argument, it only manages to compile if the argument being passed is declared as a non-const array of that type.
char char_array[] = "works";
const char const_char_array[] = "error";
char *char_ptr = "error";
const char *const_char_ptr = "error";
The relevant error in Clang (ver. 3.0-6) (errors for char_ptr and const_char_ptr are the same):
func_ptr.cpp:29:9: error: no matching function for call to 'foo'
foo( add_strlen<const_char_array> );
^~~
func_ptr.cpp:6:5: note: candidate function not viable: no overload of 'add_strlen' matching 'my_func_ptr' (aka 'int (*)(int)') for 1st argument
int foo( my_func_ptr f )
Can anyone explain to me why this is? The way I see it, template parameter S is expected to be of type const char*, which in any other circumstance means I can pass in any const or non-const pointer or array of type char and expect it to work. I would like to be able to declare my arrays as const, because I don't want to even imply that they are meant to be modified at runtime. Is there any way to keep my arrays const and use them as template arguments?
Edit: Thanks to some help (and a newer version of Clang with better errors) I was able to determine that supplying a template argument with internal linkage is part of the problem. By declaring the above variables as extern, I am able to use add_strlen<const_char_array> without error. I've also created a simplified test case. It is included below:
#include <cstring>
typedef int (*my_func_ptr)( int );
int foo( my_func_ptr f ) {
static int i = 0;
return i = f( i );
}
template<const char* S>
int add_strlen( int i ) {
return i + strlen( S );
}
extern char char_array[];
extern const char const_char_array[];
extern char *char_ptr;
extern const char *const_char_ptr;
char char_array[] = "foo";
const char const_char_array[] = "bar";
// assigning to string literal is deprecated
char *char_ptr = char_array;
const char *const_char_ptr = "baz";
int main(int argc, const char *argv[])
{
foo( add_strlen<char_array> ); // works
foo( add_strlen<const_char_array> ); // works
//foo( add_strlen<char_ptr> ); // doesn't work
//foo( add_strlen<const_char_ptr> ); // doesn't work
return 0;
}
The error seems to be related to what you are and what you are not allowed to use as non-type template parameters, referring to IBM Linux Compilers documentation for Non-type template parameters they have this to say:
The syntax of a non-type template parameter is the same as a declaration of one of the following types:
integral or enumeration
pointer to object or pointer to function
reference to object or reference to function
pointer to member
The reason why char_array[] and const_char_array[] work when passed in is because they are constant at compile time and will never change underneath the program while it is running. Integral types can be passed in, pointers to integral types however can not be passed in.
The template is expecting a type of const char * a.k.a const char[x], but it is also expecting something that will never change, so the location where the pointer is pointing may never change. When passed in at compiler time your const_char_array it is being passed a char[6] ("error"). The location will never change and the contents will never change. However when passing in the const_char_ptr it is getting a const char *, while the pointer itself may never change, it is entirely possible the location where it points may change. It itself is not static.
char *_arr = new char[20];
const char* _ptr_arr = _arr;
We can agree here that my _ptr_arr is the exact same type as your const_char_ptr, yet the location where the contents are stored may change at run-time. In templates that isn't allowed since it may require a whole new instantiation of the template, and is non-deterministic from when templates are created. A char [6] is static and won't change.
foo( add_strlen<_ptr_arr> );
results in the following compiler error:
test.cpp:36:5: error: no matching function for call to 'foo'
foo( add_strlen<_ptr_arr>);
^~~
test.cpp:6:5: note: candidate function not viable: no overload of 'add_strlen' matching 'my_func_ptr' (aka 'int (*)(int)') for 1st argument
int foo( my_func_ptr f ) {
^
Which is not very helpful, we want to figure out why there is no valid overload, compiling the code with the function stand-alone without being passed as a function pointer we get the following:
add_strlen<_ptr_arr>(0);
will result in:
test.cpp:36:5: error: no matching function for call to 'add_strlen'
add_strlen<_ptr_arr>(0);
^~~~~~~~~~~~~~~~~~~~
test.cpp:16:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'S'
int add_strlen( int i ) {
^
So the explicitly-specified argument is invalid, specifically, we can't pass in an pointer to an integral.