dcsimg
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12

Thread: problem for defining template class

  1. #1
    Join Date
    Oct 2002
    Location
    UK
    Posts
    200

    problem for defining template class

    Hi all:

    I tried to define a template class which contains a member function. This member function has an argument whose type is the typename T.
    Code:
    template <typename T1>
    class A
    {
    public:
      A() {}
     ~A() {}
    
      void memFunction( T1 arg1 )
      {
         // if arg1 is not a pointer, then implement the following line
          arg1.itsMemberFunc();
         // If arg1 is a pointer, then implement this line
          arg1->itsMemberFunc();
      }
    };
    In an application, I will apply the template and the member function.
    Code:
    int main()
    {
      A<AnotherClass> aDouble;
      AnotherClass var1;
      aDouble.memFunction( var1 );
    
      A<AnotherClass*> anotherClass;
      AnotherClass* var2 = new AnotherClass;
      anotherClass.memFunction( var2 );
    
      return 0;
    }
    You may have found that the template won't be compiled as for the line
    aDouble.memFunction( var1 ); in main(), "arg1->" can't be recoginised.

    So how can I solve this problem? THank you very much.

  2. #2
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: problem for defining template class

    Quote Originally Posted by Xiaolei Shang View Post
    Code:
         // if arg1 is not a pointer, then implement the following line
          arg1.itsMemberFunc();
         // If arg1 is a pointer, then implement this line
          arg1->itsMemberFunc();
    You can do this either by overloading the member function or by providing the class with a policy template argument to get a reference from a T.
    However, this looks very strange, so I wonder what you are trying to achieve.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  3. #3
    Join Date
    Oct 2002
    Location
    UK
    Posts
    200

    Re: problem for defining template class

    Quote Originally Posted by D_Drmmr View Post
    You can do this either by overloading the member function or by providing the class with a policy template argument to get a reference from a T.
    However, this looks very strange, so I wonder what you are trying to achieve.
    Thank you D_Drmmr. But I don't quite get your idea. In your first option, when you say "overloading the member function", do you mean I may do following like normal class overloading functions?
    Code:
    void memFunction( T1* arg1 )
    {
    ...
    }
    If so, this can't work because in main(), if you passed "AnotherClass*" type to memFunction(), the template class still look at it as T rather than T*. If my understanding is wrong, please correct me.

    For your second option that you told me, I don't quite understand it. Would like mind to give me more details? Thank you very much.

    Yes, this is strange. Actually, in my case, my template class takes a function pointer, and the memFunction() takes a pointer of AnotherClass. Then in the memFunction(), it will use the pointer to the function pointer to call some functions in AnotherClass. It's bit of messy. To simplify my question, my initial question should tell you what problem that I have basically.

  4. #4
    Join Date
    Apr 1999
    Posts
    27,449

    Re: problem for defining template class

    Quote Originally Posted by Xiaolei Shang View Post
    You may have found that the template won't be compiled as for the line
    aDouble.memFunction( var1 ); in main(), "arg1->" can't be recoginised.

    So how can I solve this problem? THank you very much.
    Read up on policies and templates. You need to tell the template how to call the function in question, and that is done by supplying an addition template parameter denoting how the template is supposed to "behave",

    Here is a quick and dirty solution (not the best, but hopefully illustrates the point).
    Code:
    template <typename T>
    struct PointerTraits
    {
    public:
        void itsMemberFunc(T* arg) 
        { return arg->itsMemberFunc(); }
    };
    
    template <typename T>
    struct ValueTraits
    {
    public:
        void itsMemberFunc(T arg) 
        { return arg.itsMemberFunc(); }
    };
    
    template <typename T1, 
              typename theTraits = ValueTraits<T1> >
    class A
    {
    public:
        A() {}
        ~A() {}
    
        void memFunction( T1 arg1 )
        {
            theTraits().itsMemberFunc(arg1);
        }
    };
    
    struct foo
    {
        void itsMemberFunc();
    };
    
    int main()
    {
        A<foo> aDouble;
        foo var1;
        aDouble.memFunction( var1 );
    
        A<foo*, PointerTraits<foo> > anotherClass;
        foo* var2 = new foo;
        anotherClass.memFunction( var2 ); 
    
        return 0;
    }
    So if you're passing a pointer, you tell the template to use pointer semantics, otherwise use value semantics (value semantics are assumed by default). Note the trickery in the template -- instead of calling the member function directly, it calls the policy's function and the policy knows how to call the function, whether it is a value or pointer.

    If you want a better real-life example, look at std::string. It really is a template:
    Code:
    typedef basic_string<char, char_traits<char> > string;
    The second template parameter is a policy that tells how to collate, compare, characters.

    Regards,

    Paul McKenzie

  5. #5
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: problem for defining template class

    Quote Originally Posted by Xiaolei Shang View Post
    If so, this can't work because in main(), if you passed "AnotherClass*" type to memFunction(), the template class still look at it as T rather than T*. If my understanding is wrong, please correct me.
    Yes, but you did not explain how the class needs to use the template argument (and it's still not clear to me). In your example, there is no need for a class at all, so you might as well use an overloaded template function.
    Quote Originally Posted by Xiaolei Shang View Post
    For your second option that you told me, I don't quite understand it. Would like mind to give me more details? Thank you very much.
    Just search for "C++ policy" and you'll find lots to read about it.
    Quote Originally Posted by Xiaolei Shang View Post
    Yes, this is strange. Actually, in my case, my template class takes a function pointer, and the memFunction() takes a pointer of AnotherClass. Then in the memFunction(), it will use the pointer to the function pointer to call some functions in AnotherClass.
    If you are trying to write a function wrapper, have a look at boost::function or std::function if your compiler supports it.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  6. #6
    Join Date
    Oct 2002
    Location
    UK
    Posts
    200

    Re: problem for defining template class

    Hi Paul:

    Thank you very much for the detailed explanation. I really appreciate for this. I also get some idea about this.

    I notice that in your main() function, you tell the template to use pointer or value when you define the object. However, if I did not tell the the template the passed argument is a pointer or value, Is there a way within the template to tell the passed argument is a poitner or value? For example:

    Code:
    int main()
    {
        A<foo> aDouble;
        foo var1;
        aDouble.memFunction( var1 );
    
        foo* var2 = new foo;
      
       // Here if we do not define the new object will be passed a pointer or
       // value using the template policy argument. Is there a way within the template to sort this problem out by itself?
        A<foo*> anotherClass;
        anotherClass.memFunction( var2 );
    
        return 0;
    }

  7. #7
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: problem for defining template class

    Here's another method you could try. It uses specialised 'Value' template classes to return a reference to the argument passed. If the argument is a pointer then it is dereferenced.
    Code:
    // Returns a reference to the value.
    template <typename T>
    struct Value
    {
        T& operator()(T &t)
        {
            return t;
        }
    };
    
    // Dereferences the pointer and returns a reference to the value.
    template <typename T>
    struct Value<T *>
    {
        T& operator()(T *t)
        {
            return *t;
        }
    };
    
    template <typename T1>
    class A
    {
    public:
      A() {}
     ~A() {}
    
      void memFunction( T1 arg1 )
      {
          // Call the member function.
          Value<T1>()(arg1).itsMemberFunc();
      }
    };
    
    class AnotherClass
    {
    public:
        void itsMemberFunc()
        {
        }
    };
    
    int main()
    {
      A<AnotherClass> aDouble;
      AnotherClass var1;
      aDouble.memFunction( var1 );
    
      A<AnotherClass*> anotherClass;
      AnotherClass* var2 = new AnotherClass;
      anotherClass.memFunction( var2 );
    
      return 0;
    }
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  8. #8
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: problem for defining template class

    Quote Originally Posted by Xiaolei Shang View Post
    You may have found that the template won't be compiled as for the line
    aDouble.memFunction( var1 ); in main(), "arg1->" can't be recoginised.

    So how can I solve this problem? THank you very much.
    To me, it is very important to make the distinction between the parameter type, and the argument type relative to the parameter: To you want the behavior to change depending on the parameter T, or on the argument passed to the method?

    IMO, different parameters should not change the behavior of your template from a generic point of view. If your template expects a class, then the correct solution is to simply not compile until the parameter is correct.

    NOW, given a parameter, you can have the function take an argument of either pointer or type, of the parameter type.

    Code:
    #include <iostream>
    
    template <typename T>
    class string_operation
    {
    public:
      static void do_it(T i)
      {
        std::cout << i << ": ";
      }
    
      static void print_it(T i)
      {
        do_it(i);
        std::cout << "pass by value" << std::endl;
      }
    
      static void print_it(const T* i)
      {
        if(i == 0) return;
        do_it(*i);
    
        std::cout << "pass by pointer." << std::endl;
      }
    };
    
    int main()
    {
      const std::string* pString = new std::string("I am an std::string");
      const char* aChars  = "I am a char*";
    
      string_operation<std::string>::print_it(pString);
      string_operation<const char*>::print_it(aChars);
    }
    Run this code, and observe how my argument of type "char*" is passed by value, yet my "std::string" is passed by pointer.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  9. #9
    Join Date
    Oct 2011
    Posts
    59

    Re: problem for defining template class

    What JohnW is doing is called template partial specialization. It is a good way to write custom code for particular types that are sent in. It is used in template metaprogramming. If you are interested, you can find a lot of (maybe overwhelmingly so if you are new to C++) here:

    http://www.boost.org/doc/libs/1_40_0...etaprogramming

    Boost is a great reference and library that I use all the time.

    Oh, and please note that though you can do partial specialization for functions as well, it may not work as expected. It is far more easier to understand when used with classes.

    Hope this helps.


    A

  10. #10
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    Re: problem for defining template class

    Quote Originally Posted by adrian_h View Post
    Oh, and please note that though you can do partial specialization for functions as well, it may not work as expected. It is far more easier to understand when used with classes.
    Nice post, however, I thought that I would point out that the partial template specialisation of a function is not allowed in C++. You can template functions, and fully specialise template functions, but you cannot partially specialise them. Instead, the C++ standard allows template functions to be overloaded in the same way as non-template functions. This means that whilst you cannot partially specialise them i.e.

    Code:
    #include <iostream>
    
    template <typename T, typename U>
    void function_test(T t, U u)
    {
      std::cout << t << "  " << u << std::endl;
    }
    
    template <typename T>
    void function_test<T, int>(T t, int u) //Red part not allowed
    {
      std::cout << t << " " << u << std::endl;
    }
    
    int main()
    {
      function_test("hello", 52);
    }
    You can write an overload

    Code:
    #include <iostream>
    
    template <typename  T, typename U>
    void function_test(T t, U u)
    {
      std::cout << t << "  " << u << std::endl;
    }
    
    template <typename  T>
    void function_test(T t, int u) //Red part removed - now allowed
    {
      std::cout << t << " " << u << std::endl;
    }
    
    int main()
    {
      function_test("hello", 52);
    }
    I hope this helps.

  11. #11
    Join Date
    Oct 2011
    Posts
    59

    Re: problem for defining template class

    Quote Originally Posted by PredicateNormative View Post
    Nice post, however, I thought that I would point out that the partial template specialisation of a function is not allowed in C++. You can template functions, and fully specialise template functions, but you cannot partially specialise them. Instead, the C++ standard allows template functions to be overloaded in the same way as non-template functions. This means that whilst you cannot partially specialise them i.e.
    ...
    Yeah, that's what I meant. Nice catch PN.


    A

  12. #12
    Join Date
    Oct 2002
    Location
    UK
    Posts
    200

    Re: problem for defining template class

    Sorry for the late response. Thank you all. All your suggestions are valueable for me. Based on your suggestions, I figured out the solution like the following:
    Code:
    struct value_tag {};
    struct pointer_tag {};
    
    template<typename T>
    struct function_traits
    {
      typedef value_tag function_categrory;
    };
    
    template<typename T>
    struct function_traits<T*>
    {
      typedef pointer_tag function_categrory;
    };
    
    template <typename T1>
    class A
    {
    public:
      A() {}
     ~A() {}
    
    void doFunction( T& arg, value_tag )
    {
        arg.itsMemberFunc();
    }
    
    void doFunction( T* arg, pointer_tag )
    {
        arg->itsMemberFunc();
    }
    
    void memFunction( T arg )
    {
       doFunction( arg, function_traits<T>::function_categrory() );
    }
    
    };
    So in a main file, it works like this:
    Code:
    class AnotherClass
    {
    public:
        void itsMemberFunc()
        {
        }
    };
    
    int main()
    {
      A<AnotherClass> aDouble;
      AnotherClass var1;
      aDouble.memFunction( var1 );
    
      A<AnotherClass*> anotherClass;
      AnotherClass* var2 = new AnotherClass;
      anotherClass.memFunction( var2 );
    
      return 0;
    }
    This method maybe not a better one. But it works for my case. Thank you very much again. This is a really good lesson for me.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width




On-Demand Webinars (sponsored)