Templated friends syntax

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Banfa
    Recognized Expert Expert
    • Feb 2006
    • 9067

    Templated friends syntax

    So I have a little problem, I have a template class and that class contains a template function; now what I want to do is declare that function in the class (or indeed the entire class) as a friend of all specialisations of the class.

    I did that (or thought I did) but the code I produced compiles with gcc 3.4.2 but not with Microsoft Visual Studio 2008 (Express Edition). So I have reduced my code to a minimum compilable example that exhibits the behaviour as follows
    Code:
    template<class T>
    class Example
    {
    template<class TT> template<class RHS> friend void Example<TT>::copy(RHS& rhs);
    
    public:
    	// Default constructor
    	Example() : data(0) { }
    
    	//Destructor deletes managed object when reference count is zero
    	~Example(){ delete data; }
    
    
    	template<class R>
    	R* asType() { return data; }
    
    	template<class R>
    	const R* asType() const { return data; }
    
    	template<class RHS>
    	void copy(RHS& rhs);
    
    protected :
    	T* data;
    };
    
    template<class T>
    template<class RHS>
    void Example<T>::copy(RHS& rhs)
    {
    	this->~Example();
    
    	data = rhs.template asType<T>();
    }
    
    
    int main(int, char**)
    {
    	Example<int> ei;
    	
    	Example<int> el;
    	
    	ei.copy<Example<int> >(el);
    }
    One of the results of the production is that the code does appear to make logical sense, that is it appears more complex than required, however it does require that level of complexity in the full code.

    So for gcc 3.4.2 using the command line

    g++ -Wall -pendantic TemplateText.cp p

    compiles into an executable without producing any compiler diagnostic messages.

    However for Microsoft cl version 15.00.30729.01 (as shipped with Visual Studio 2008 Express Edition) the following errors are produced

    Code:
    TemplateTest.cpp(4) : warning C4346: 'Example<T>::copy' : dependent name is not a type
            prefix with 'typename' to indicate a type
            TemplateTest.cpp(25) : see reference to class template instantiation 'Example<T>' being compiled
    TemplateTest.cpp(4) : error C2998: 'Unique-Type-copy copy' : cannot be a template definition
    TemplateTest.cpp(8) : error C3861: 'data': identifier not found
    TemplateTest.cpp(8) : error C2461: 'Example<T>' : constructor syntax missing formal parameters
    TemplateTest.cpp(8) : error C2473: '{ctor}' : looks like a function definition, but there is no parameter list.
    TemplateTest.cpp(11) : error C2143: syntax error : missing ';' before '~'
    TemplateTest.cpp(34) : error C2039: 'copy' : is not a member of 'Example<T>'
    TemplateTest.cpp(4) : warning C4346: 'Example<T>::copy' : dependent name is not a type
            prefix with 'typename' to indicate a type
            TemplateTest.cpp(39) : see reference to class template instantiation 'Example<T>' being compiled
            with
            [
                T=int
            ]
    TemplateTest.cpp(4) : error C2998: 'Unique-Type-copy copy' : cannot be a template definition
    TemplateTest.cpp(8) : error C3861: 'data': identifier not found
    TemplateTest.cpp(8) : error C2461: 'Example<T>' : constructor syntax missing formal parameters
            with
            [
                T=int
            ]
    TemplateTest.cpp(8) : error C2473: '{ctor}' : looks like a function definition, but there is no parameter list.
    TemplateTest.cpp(11) : error C2143: syntax error : missing ';' before '~'
    TemplateTest.cpp(43) : error C2039: 'copy' : is not a member of 'Example<T>'
            with
            [
                T=int
            ]
    So can anyone here verify that the code on line 4 is in fact standard conforming syntax or show that it isn't?

    Alternatively can anyone think of a way of solving the problem described in the first paragraph?
  • weaknessforcats
    Recognized Expert Expert
    • Mar 2007
    • 9214

    #2
    It looks like you want an unbounded friend function in the Example class.

    Unbounded friends require the template for the friend be embedded in the class so the compiler has access to it.

    Bounded friends are specializations so in that case all you need is a function prototype showing the correct type.

    This compiles using Visual Studio.NET 2008:

    template<class T>
    Code:
    class Example 
    { 
    friend class RHS;
    friend void copy(RHS& rhs)
    { 
        this->~Example(); 
      
        data = rhs.template asType<T>(); 
    } 
    etc....

    Comment

    • RRick
      Recognized Expert Contributor
      • Feb 2007
      • 463

      #3
      In some cases, templates have trouble figuring out the type of what something is. I don't know the specifics of what causes this, but sometimes an explicit "typename" is needed in a template declaration.

      Try googling for "c++ difference between typename and class". It returns some interesting answers.

      Comment

      • weaknessforcats
        Recognized Expert Expert
        • Mar 2007
        • 9214

        #4
        The answer is:

        Older C++ implementations used class in templates to identify a type:

        Code:
        template<class T>
        void func()
        {
            T data;
        }
        even though T may not be a class. Like it could be an int or a double.

        Newer C++ implementations use typename instead of class to better communicate that you are dealing with a type, whether it is a class ot not.

        Code:
        template<typename T>
        void func()
        {
            T data;
        }
        Prefer typename to class in templates.

        Comment

        • Banfa
          Recognized Expert Expert
          • Feb 2006
          • 9067

          #5
          The explicit typename is need where you are using the templated type to access a type contained in the templated type. For instance

          Code:
          template<typename T>
          class MyTemplateClass
          {
          public:
              // constructors methods etc.
          
          protected
              typename T::size_type size;
          }
          typename is required to tell the compiler that T::size_type refers to a type defined in T. In my case the compiler has got confused and suggested I have left out a required typename, however I copy is a function not a type so this doesn't apply.

          Comment

          • weaknessforcats
            Recognized Expert Expert
            • Mar 2007
            • 9214

            #6
            That's true. It used to be you had to code:

            Code:
            template<class T> 
            class MyTemplateClass 
            { 
            public: 
                // constructors methods etc. 
              
            protected:
                class T::size_type size; 
            };
            So in those cases where T was not a class, your code looked odd. So they changed it to typename.

            Comment

            Working...