views:

355

answers:

3

I have a class that I've been provided that I really don't want to change, but I do want to extend. I'm a pattern and template newbie experimenting with a Decorator pattern applied to a template class. Template class contains a pointer-to-member (if I understand the semantics correctly) in yet another class. The pointer-to-member is the deserializer of an XML istream. The type 'T' is the type of XML document to be deserialized.

template <typename T> class B {
public:
  typedef std::auto_ptr<T> MYFUN( 
    std::istream&, const std::string&, const std::string& );

public:
  B<T>( MYFUN* p );

private:
  MYFUN *fptr;
  std::string aString1;
  std::string aString2;

};

The typedef looks odd to me after reading http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.5, and yet this class seems to work fine as-is. There aren't any additional #defines in the provided header file, so this is a little mysterious to me.

Now I try to extend it, as Decorator because I want to do a bit more work on the auto_ptr object returned by MYFUN:

template <typename T>
class D : public class B<T>
{
  D( B<T>::MYFUN *fPtr, B<T> *providedBase ); //compiler complaint
  //Looks like B
  private:
    B* base_;

};

template <typename T>
D<T>::D( B<T>::MYFUN *p, B<T> *base ) //compiler complaint
:
B<T>::B( p ), base_(providedBase)
{ }

When trying to compile this, I get a syntax complaint at the two lines shown. Error is something like "expected ')' at *". There is no complaint about MYFUN being undefined.

When I re-define the pointer-to-member in D with the same signature as in D, i.e.

//change MYFUN to NEWFUN in D)
typedef std::auto_ptr<T> MYNEWFUN( 
    std::istream&, const std::string&, const std::string& );

This works. I prefer not to have to do this for every D/Decorator I might make of B. I tried to perform the typedef more globally, but couldn't get the syntax right due to the template parameter being undefined.

+1  A: 

The definition of the MYFUN typedef in B is done with private visibility. D will not be able to access it. If you change it to protected or public, does it then work?

template <typename T> class B {
  protected:
    typedef std::auto_ptr<T> MYFUN( 
      std::istream&, const std::string&, const std::string& );
...
};
1800 INFORMATION
I mistakenly left off the 'public' declaration
A: 

The problem I see with this is that B::MYFUN is a private typedef.

Therefore, any inheriting class cannot access it.

Change this to:

template <typename T> class B 
{  
public:
   typedef std::auto_ptr<T> MYFUN(     std::istream&, const std::string&, const std::string& );
public:  
   B<T>( MYFUN* p );
private:  
   MYFUN *fptr;  
std::string aString1;  
std::string aString2;
};
Andrew Shepherd
I mistakenly left off the 'public' declaration
A: 

The compile error is due to the fact that the compiler can't tell you are talking about a type.

Try:

D( typename B<T>::MYFUN *fPtr, B<T> *providedBase );

and

template <typename T>
D<T>::D( typename B<T>::MYFUN *p, B<T> *base )

See: the templates section of the C++ FAQ Lite for more details on why this is necessary, but the summary is that because of the possibility of template specialization, there is no way for the compiler to be sure that B<T>::MYFUN is actually referring to a type.

Joe
That's it! Thanks very much!!