Thread: Template specialization

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

    Template specialization

    I have a class I called concatenation_iterator, which concatenates two other iterators. This means that it gives the results of the first iterator until it reaches its end, then it continues with the second.

    The class is designed to work with all iterator categories except output and even mixed categories (the category of the resulting iterator is the lesser of the two source categories). However this gives me a problem.

    Input and forward iterators have only pre- and postfix ++ operators.
    Bidirectional iterators add pre- and postfix -- operators.
    Random Access iterators add += and + operators.

    How can I specialize my class to add these operators without having to repeat the whole main content?

    I know I can do something like
    Code:
    template<typename T>
    class A {
      void fun();
    };
    template<>
    class A<int> {
      void fun();
      void nofun();
    }
    but fun() represents quite a lot of code, which I don't want to repeat. Is there a way to achieve something like
    Code:
    template<typename T>
    class A {
      void fun();
    };
    template<>
    class A<int> {
      using A<T>;
      void nofun();
    }
    ?

    Thanks in advance.

    Here's the concatenation iterator as it is now.
    Code:
    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;
    	}
    
    	// 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; }
    
    	// Bidir needs --, Random needs += and +!
    };
    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
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Use inheritence and template specialization. Put all common members and methods in a base class. Inheret base class to define templated type. Then all specializations only have to duplicate constructors and destructors
    Here's what I mean:
    Code:
    #include <iostream>
    using namespace std;
    
    // members and methods common to all specializations of A<>
    template<typename T>
    struct A_base
    {
        T m_n;
        A_base(const T &n) : m_n(n) {}
    
        void foo() {cout << "foo: " << m_n << endl;}
    };//A_base
    
    template<typename T>
    struct A : public A_base<T>
    {
        A(const T &n) : A_base<T>(n) {}
    };//A
    
    template<>
    struct A<int> : public A_base<int>
    {
        A(const int &n) : A_base<int>(n) {}
        void foo2() {cout << "foo<int>: " << m_n << endl;}
    };//A<int>
    
    int main()
    {
        A<char> ca('c');
        A<int> ia(69);
    
        ca.foo();
        ia.foo();
        ia.foo2();
    
        return 0;
    }//main
    gg

  3. #3
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Thanks, the same idea came to me last night.

    Ah, nothing like a good night's thinking to get you on track


    Thanks again.
    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. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  2. error: template with C linkage
    By michaels-r in forum C++ Programming
    Replies: 3
    Last Post: 05-17-2006, 08:11 AM
  3. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM
  4. Template function specialization
    By thomas.behr in forum C++ Programming
    Replies: 4
    Last Post: 06-03-2003, 11:50 AM
  5. oh me oh my hash maps up the wazoo
    By DarkDays in forum C++ Programming
    Replies: 5
    Last Post: 11-30-2001, 12:54 PM