views:

143

answers:

4

I've this class

namespace baseUtils {

template<typename AT>
class growVector {

     int size;
     AT **arr;
     AT* defaultVal;

    public:

     growVector(int size, AT* defaultVal );   //Expects number of elements (5) and default value (NULL)
     AT*& operator[](unsigned pos);
     int length();
     void reset(int pos); //Resets an element to default value
     void reset();   //Resets all elements to default value
     ~growVector();
};

}

and this is the implementation for operator[]

template<typename AT>
AT*& growVector<AT>::operator [](unsigned pos){
    if (pos >= size){
     int newSize = size*2;
     AT** newArr = new AT*[newSize];
     memcpy(newArr, arr, sizeof(AT)*size);
     for (int i = size; i<newSize; i++)
      newArr[i] = defaultVal;
     size = newSize;
     delete arr;
     arr = newArr;
    }
    return arr[pos];
}

(yes I do realize i don't check if size*2 >= pos... but that's not the point now) if I use it in code like:

int main() {

    growVector<char> gv();
    char* x = NULL;
    for (int i = 0; i< 50; i++){
     gv[i] = x;
    }
    gv.reset();
    return 0;
}

the compiler says

../src/base.cpp:98: warning: pointer to a function used in arithmetic
../src/base.cpp:98: error: assignment of read-only location ‘*(gv + ((unsigned int)i))’
../src/base.cpp:98: error: cannot convert ‘char*’ to ‘baseUtils::growVector<char>()’ in assignment

referring to the line gv[i] = x; (seems like it doesn't see the redefinition of [])

Why???? What am I missing?

+9  A: 

The problem is your declaration

growVector<char> gv();

The compiler interprets this as declaring a function called gv which returns a growVector<char>, not as an object as you indend. Since there isn't a default constructor, this wouldn't compile anyway. Change it to:

growVector<char> gv(0,0);
Mike Seymour
lol i really wasn't looking at it... sorry what a shame... XD
gotch4
+4  A: 

The compiler thinks this line

growVector<char> gv();

is declaring a function, rather than a variable. Drop the () and things should work.

Novelocrat
A: 

After correcting the constructor problem I've the linker sayng:

/home/dario/workspace/base/Debug/../src/base.cpp:95: undefined reference to `baseUtils::growVector<char>::growVector(int, char*)'
/home/dario/workspace/base/Debug/../src/base.cpp:98: undefined reference to `baseUtils::growVector<char>::operator[](unsigned int)'
/home/dario/workspace/base/Debug/../src/base.cpp:100: undefined reference to `baseUtils::growVector<char>::reset()'
/home/dario/workspace/base/Debug/../src/base.cpp:101: undefined reference to `baseUtils::growVector<char>::~growVector()'
/home/dario/workspace/base/Debug/../src/base.cpp:101: undefined reference to `baseUtils::growVector<char>::~growVector()'

like it cannot link... why??? :O

gotch4
I moved that to the question, this is not a forum, you should not expect people to read all the answers and the order is not preserved (because of the votes).
Matthieu M.
Although templates were designed with the intention of being able to put the declaration in the header and the implementation in a .cpp file, in practice that isn't implemented (except by Comeau). Cfront actually had this ability but it's not common anymore ( http://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html ). The main solution is to roll the declaration into the definition and put it in the header.
Max Lybbert
+1  A: 

I just would like to point out that it is a good practice to have two versions of subscript [] operator in the class: const (which will be used for r-value) and non-const. You have implemented non-const version but it can not be used in const functions or in any function that receive instance of your class as const reference or pointer pointer to const.

BostonLogan