views:

135

answers:

2

Hi all I'm having trouble with C++ template operator=

What I'm trying to do: I'm working on a graph algorithm project using cuda and we have several different formats for benchmarking graphs. Also, I'm not entirely sure what type we'll end up using for the individual elements of a graph.
My goal is to have a templated graph class and a number of other classes, each of which will know how to load a particular format. Everything seems to work alright except the point where the graphCreator class returns a graph type from the generate function. Here is my code:

Graph opertator=:

      MatrixGraph<T>& operator=(MatrixGraph<T>& rhs)
      {
         width = rhs.width;
         height = rhs.height;
         pGraph = rhs.pGraph;
         pitch = rhs.pitch;
         sizeOfGraph = rhs.sizeOfGraph;    
         rhs.Reset();
      }

the rhs.reset() call removes all references to allocated memory so they will not be deallocated by rhs. Only one graph is allowed to have a reference to the allocated graph memory.

Graph copy constructor:

   MatrixGraph(MatrixGraph<T>& graph)
   {
        (*this) = graph;
   }

Graph Creator load function:

MatrixGraph<T> LoadDIMACSGraphFile(std::istream& dimacsFile)
{
char inputType;
std::string input;

GetNumberOfNodesAndEdges(dimacsFile, nodes, edges);

MatrixGraph<T> myNewMatrixGraph(nodes);

while(dimacsFile >> inputType)
{
  switch(inputType)
  {
    case 'e':
      int w,v;
      dimacsFile >> w >> v;
      myNewMatrixGraph[w - 1][v - 1] = 1;
      myNewMatrixGraph[v - 1][w - 1] = 1;
      break;

    default:
      std::getline(dimacsFile, input);
      break;
  }
}

  return myNewMatrixGraph;
}

And finally in main.cpp where I'm trying to unit test this I use it:

DIMACSGraphCreator<short> creator;
myGraph = creator.LoadDIMACSGraphFile(instream);

When I try to compile I get this error:

main.cpp: In function 'int main(int, char**)':
main.cpp:31: error: no match for 'operator=' in 'myGraph = DIMACSGraphCreator<T>::LoadDIMACSGraphFile(std::istream&) [with T = short int](((std::istream&)(& instream.std::basic_ifstream<char, std::char_traits<char> >::<anonymous>)))'
MatrixGraph.h:103: note: candidates are: MatrixGraph<T>& MatrixGraph<T>::operator=(MatrixGraph<T>&) [with T = short int]
make: *** [matrixTest] Error 1
+3  A: 

just a guess, are you by chance missing const qualifiers in your copy constructor and assignment?

aaa
+1  A: 

The problem is you're returning by value (correctly) but trying to bind that temporary object to a non-const reference (for the op= parameter). You can't do this.

The solution is to change things around, which can result in non-idiomatic code; use an auto_ptr_ref-like construct, which gets around this in a fairly bad-but-encapsulated way; or use r-value references, which are designed for exactly this situation. However, r-value references are only available as part of C++0x, and your compiler may not support them yet.

Make sure to return *this in your op= as well. Without warnings turned on your compiler may silently (and against the standard) accept that function without a return statement. (I don't know why.)

Example of the first solution:

// move return value into output-parameter:
void LoadDIMACSGraphFile(std::istream& dimacsFile, MatrixGraph<T>& dest);

// ...

DIMACSGraphCreator<short> creator;
creator.LoadDIMACSGraphFile(instream, myGraph);

std::auto_ptr is in the the stdlib, and uses a special "holder" class named auto_ptr_ref to implement move semantics.

Roger Pate