Thread: Partial specialization of class template.

  1. #1
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895

    Partial specialization of class template.

    I have a class template:
    Code:
    template<typename T1, typename T2>
    class A
    {
    public:
      void f1();
      void f2();
      void f3();
      int f4();
    };
    The class is actually much longer.

    Now, in case the second template parameter is float, f4 should return std::string instead of int.
    Code:
    template<typename T1>
    class A<T1, float>
    {
    public:
      void f1();
      void f2();
      void f3();
      std::string f4();
    };
    Is there any way to accomplish this without specifying all of the other parts of the class again?

    What I'm really trying to do is writing a concatenation_iterator that runs through two iterators in succession. If those iterators are of input iterator category, the postfix ++ operator should return a proxy object, for other categories it should return a copy of itself as is the normal behaviour of postfix ++.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  2. #2
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    You could try using a second template acting as a functor, specialise operator() and then use that as a public member. A bit "round the houses", but it might have potential for what you want to do;

    Code:
    #include <iostream>
    #include <string>
    
    template<typename T3>
    struct f4_
    {
    	int operator()(){return 1;}
    };
    
    template<>
    struct f4_<float>
    {
    	std::string operator()(){return "FOOBAR";}
    };
    
    template<typename T1, typename T2>
    class A
    {	
    public:
      	void f1();
      	void f2();
      	void f3();
      	f4_<T2> f4;
    };
    
     
    int main()
    {
    	A<int,int> foo;
    	A<int,float> bar;
    	
    	std::cout << "foo Answer = " << foo.f4() << std::endl;
    	std::cout << "bar Answer = " << bar.f4() << std::endl;
    
    }

  3. #3
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Unfortunatly that solution is not possible in my case as the function in question is an overloaded operator.

    Thanks anyway. I've solved it via template metaprogramming :)

    So in case anyone ever needs to concatenate two containers or anything like that:
    Code:
    #ifndef _MOREITER_HPP_SR_H_
    #define _MOREITER_HPP_SR_H_
    
    #include <iterator>
    #include <boost/iterator.hpp>
    #include <boost/type_traits.hpp>
    #include <boost/mpl/if.hpp>
    
    namespace boost
    {
    	namespace internal
    	{
    		// Gets the lesser iterator category of the two arguments
    		// Possible combinations:
    		// Combination  Handled By  Result
    		// II           IU          I
    		// FI           FI          I
    		// BI           UU          IB -> I
    		// RI           UU          IR -> I
    		// IF           IU          I
    		// FF           FU          F
    		// BF           UU          FB -> F
    		// RF           UU          FR -> F
    		// IB           IU          I
    		// FB           FU          F
    		// BB           BB          B
    		// RB           UU          BR -> B
    		// IR           IU          I
    		// FR           FU          F
    		// BR           BR          B
    		// RR           RR          R
    
    		// A version that compiles without partial spec. would have to explicitly
    		// handle more cases.
    
    		// UU
    		template<typename LCAT, typename RCAT>
    		struct lesser_category
    		{
    			typedef typename lesser_category<RCAT, LCAT> type;
    		};
    		// IU
    		template<typename RCAT>
    		struct lesser_category<std::input_iterator_tag, RCAT>
    		{
    			typedef std::input_iterator_tag type;
    		};
    		// FU
    		template<typename RCAT>
    		struct lesser_category<std::forward_iterator_tag, RCAT>
    		{
    			typedef std::forward_iterator_tag type;
    		};
    		// FI
    		template<>
    		struct lesser_category<std::forward_iterator_tag,
    			std::input_iterator_tag>
    		{
    			typedef std::input_iterator_tag type;
    		};
    		// BB
    		template<>
    		struct lesser_category<std::bidirectional_iterator_tag,
    			std::bidirectional_iterator_tag>
    		{
    			typedef std::bidirectional_iterator_tag type;
    		};
    		// BR
    		template<>
    		struct lesser_category<std::bidirectional_iterator_tag,
    			std::random_access_iterator_tag>
    		{
    			typedef std::bidirectional_iterator_tag type;
    		};
    		// RR
    		template<>
    		struct lesser_category<std::random_access_iterator_tag,
    			std::random_access_iterator_tag>
    		{
    			typedef std::random_access_iterator_tag type;
    		};
    	}
    
    	template<typename FirstIter, typename SecondIter,
    		typename Category = internal::lesser_category<
    		typename std::iterator_traits<FirstIter>::iterator_category,
    		typename std::iterator_traits<SecondIter>::iterator_category>::type >
    	class concatenation_iterator
    		: public iterator<Category, typename std::iterator_traits<FirstIter>::value_type,
    		typename std::iterator_traits<FirstIter>::distance_type,
    		typename std::iterator_traits<FirstIter>::pointer,
    		typename std::iterator_traits<FirstIter>::reference>
    	{
    	public:
    		typedef FirstIter first_iterator_type;
    		typedef SecondIter second_iterator_type;
    		typedef concatenation_iterator<first_iterator_type, second_iterator_type,
    			Category> self;
    
    	private:
    		FirstIter begin1, end1;
    		SecondIter begin2;
    	public:
    		// Creates a begin iterator
    		concatenation_iterator(const FirstIter& b1, const FirstIter &e1, const SecondIter &b2)
    			: begin1(b1), end1(e1), begin2(b2)
    		{}
    		// Creates an end iterator
    		concatenation_iterator(const FirstIter &e1, const SecondIter &e2)
    			: begin1(e1), end1(e1), begin2(e2)
    		{}
    
    		reference operator *() { return begin1 == end1 ? *begin2 : *begin1; }
    		pointer operator ->() { return begin1 == end1 ? &*begin2 : &*begin1; }
    		self & operator ++() { if(begin1 != end1) ++begin1; else ++begin2; return *this; }
    
    		// Test the moving iterators
    		friend bool operator ==(const self &x, const self &y) {
    			return x.begin1 == y.begin1 && x.begin2 == y.begin2;
    		}
    		friend bool operator !=(const self &x, const self &y) {
    			return x.begin1 != y.begin1 || x.begin2 != y.begin2;
    		}
    
    		// This needs more thinking about - partial specialization?
    		// I may not use a proxy object for this if it's not
    		// an input iterator.
    		// But if one of the contained iterators is an input iterator
    		// and uses shallow copy then this implementation fails.
    		// Use template metaprogramming to specify the return type.
    		class postinc_proxy {
    			value_type el;
    		public:
    			explicit postinc_proxy(const self &) : el(*i) {}
    			value_type operator *() const { return el; }
    		};
    
    		typedef typename mpl::if_<is_same<Category, std::input_iterator_tag>,
    			postinc_proxy, self>::type postinc_ret;
    
    		postinc_ret operator ++(int) { postinc_ret t(*this); ++*this; return t; }
    
    	};
    
    }
    
    #endif
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  4. #4
    Normal vector Carlos's Avatar
    Join Date
    Sep 2001
    Location
    Budapest
    Posts
    463
    > Now, in case the second template parameter is float, f4 should return std::string instead of int.

    What if f4() returns std::string for int, too?

  5. #5
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Nope, not possible. Look at the long code I posted, the issue is the postfix ++ operator.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Default class template problem
    By Elysia in forum C++ Programming
    Replies: 5
    Last Post: 07-11-2008, 08:44 AM
  2. template function v.s. template class
    By George2 in forum C++ Programming
    Replies: 3
    Last Post: 12-13-2007, 01:46 AM
  3. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM
  4. Template specialization
    By CornedBee in forum C++ Programming
    Replies: 2
    Last Post: 11-25-2003, 02:02 AM
  5. include question
    By Wanted420 in forum C++ Programming
    Replies: 8
    Last Post: 10-17-2003, 03:49 AM