views:

53

answers:

2

I have a bunch of containers of object pointers that I want to iterate through in different contexts to produce diagnostics for them. I'm struggling with the syntax required to define the functions... which, on account of these objects filtering through diverse parts of my application, seem best encapsulated in a dedicated diagnostics class thus:

// Code sketch only - detail fleshed out below...  
class ObjectListDiagnoser  
{  
public:  
    static void GenerateDiagnostics( /* help required here! */ );  
};  

...

// Elsewhere in the system...  
ObjectListDiagnoser::GenerateDiagnostics( /* help required here! */ );  

What I'd like to be able to do (in places across my application) is at least this:

std::vector<MyObject *> objGroup1;  
std::list<MyObject *> objGroup2;

ObjectListDiagnoser::GenerateDiagnostics( objGroup1.begin(), objGroup1.end() );  
ObjectListDiagnoser::GenerateDiagnostics( objGroup2.begin(), objGroup2.end() );  
ObjectListDiagnoser::GenerateDiagnostics( objGroup1.rbegin(), objGroup1.rend() );  

I have tried to template my function in two ways, with no success:

class ObjectListDiagnoser  
{  
public:  
    // 1 - nope.  
    template <class ObjIter>
    static void GenerateDiagnostics( ObjIter first, ObjIter last );  
    // 2. - nope.  
    template <class Container, class ObjIter>
    static void GenerateDiagnostics( Container<MyObject *>::ObjIter first,  
                                     Container<MyObject *>::ObjIter last );  
};  

Can someone provide the correct syntax for this? The container type will vary, and the direction of iteration will vary, but always for the same type of object.


Summary of discussion in the comments below - case 1 is correct... but leads to a broadly unintelligible linker error if the template function definition is not in the header. template function definitions simply have to go in the header - a point easily forgotten. Slip it into the header, and all is well - compiles, links... and hopefully even runs.

+1  A: 

You should use option 1. As with the functions in <algorithm>, container types don't belong in template arguments.

We'll need more information about what's going wrong. You should be OK… you just need to add the definition.

template <class ObjIter>
static void ObjectListDiagnoser::GenerateDiagnostics
 ( ObjIter first, ObjIter last ) {
   …
}

EDIT: as with all templates, this definition needs to go in the header file. Using a template outside the source file it's defined in is widely unsupported.

You can use explicit instantiation, which allows implementation in a non-header file but negates some of the benefits of using templates: you can only use the template parameters which were explicitly instantiated.

// implementation in source file

template <class ObjIter>
static void ObjectListDiagnoser::GenerateDiagnostics
 ( ObjIter first, ObjIter last ) {
   …
}

template void ObjectListDiagnoser::GenerateDiagnostics
  < std::list<Object>::iterator >
 ( std::list<Object>::iterator first, std::list<Object>::iterator last );

template void ObjectListDiagnoser::GenerateDiagnostics
  < std::vector<Object>::iterator >
 ( std::vector<Object>::iterator first, std::vector<Object>::iterator last );

// now you can only use vector<Object>::iterator or list<Object>::iterator
// as arguments.
Potatoswatter
As per comment to my question... this leads to a linker error for me. The error starts with: error LNK2019: unresolved external symbol "public: static void __cdecl ObjectListDiagnoser::GenerateDiagnostics<class std::reverse_iterator<class std::list<class MyObject *,class std::allocator<class MyObject *> >::_Iterator<1> > >(class std::reverse_iterator<class std::list<class MyObject *,class std::allocator<class MyObject *> >::_Iterator<1> >, ... and goes on for more space than I have in this comment!!
omatai
Note - the above link error occurs when I invoke my function in the second case (forward pass through a std::list). I have not got as far as trying std::vector or reverse_iterator cases yet...
omatai
Apologies - I have extracted this simplified version from my code, where there are two functions. The second function is for formatting, and it's the one which passes through the list estimating the size required for the diagnostic display. The link error above is for the actual diagnostics, which does run backwards through the std::list. Both functions generate a link error. The forward pass function generates the following error...
omatai
error LNK2019: unresolved external symbol "public: static class CSize __cdecl ObjectListDiagnoser::GetDiagnosticDisplaySize<class std::list<class MyObject *,class std::allocator<class MyObject *> >::_Iterator<1> >(class std::list<class MyObject *,class std::allocator<class MyObject *> >::_Iterator<1>,class std::list<class MyObject *,class std::allocator<class MyObject *> >::_Iterator<1>,int)"
omatai
@omatai: I updated my answer. I suspect you are trying to define the function template in one `.cpp` file and use it in another.
Potatoswatter
A: 

I agree with @sth that there is no problem with 1. Infact that is how STL algorithms are declared refer - find

If 1 works there is no need for 2. Any ways its declaration should be

template <class Container>
static void GenerateDiagnostics( typename Container<MyObject *>::iterator first, 
       typename Container<MyObject *>::iterator last );  

Please note - this is just an example which would work with iterator of a container and may not work with its reverse_iterator or const_iterator

Yogesh Arora
Nope, thats not what it should look like.
Georg Fritzsche
can you please provide the correction
Yogesh Arora