[RESOLVED] Template const & non-const versions
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9

Thread: [RESOLVED] Template const & non-const versions

  1. #1
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,725

    [RESOLVED] Template const & non-const versions

    I'm pretty sure this can't be done the way I'd like, but I thought I'd put it past you lot first.

    I have two classes.

    Code:
    class Test
    {
    public:
         void Set(int &i)
         {
            p_i = &i;
         }
    
         int *Get()
         {
            return p_i;
         }
     
    private:
         int *p_i;
    };
    
    
    class Const_Test
    {
     public:
        void Set(const int &i)
        {
            p_i = &i;
        }
     
        const int *Get()
        {
            return p_i;
        }
      
    private:
         const int *p_i;
    };
    What I would like to do is have one templated class where I can specify whether to use 'const' or not.

    The only solution I have come up with so far is to specify the whole type i.e. 'int' or 'const int'

    Code:
    template <typename T>
    class Test
    {
    public:
         void Set(T &i)
         {
            p_i = &i;
         }
    
         T *Get()
         {
             return p_i;
         }
     
    private:
         T *p_i;
    };
    
    Test<int> test;
    Test<const int> const_test;
    Any alternative ideas?
    "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

  2. #2
    Join Date
    Oct 2008
    Posts
    1,163

    Re: Template const & non-const versions

    maybe something like

    Code:
    #include <boost/type_traits.hpp>
    #include <boost/mpl/identity.hpp>
    #include <boost/mpl/apply.hpp>
    
    namespace mpl = boost::mpl;
    
    
    template <typename ArgPolicy = mpl::identity<mpl::_1> >
    class Test
    {
    public:
         typedef int						BaseType;     
         typedef typename mpl::apply<ArgPolicy, BaseType>::type 	ArgType;
    
         void Set(ArgType &i)
         {
            p_i = &i;
         }
    
         ArgType *Get()
         {
             return p_i;
         }
    
    private:
         ArgType *p_i;
    };
    
    Test<> 					a;
    Test< boost::add_const<mpl::_1> > const_a;

  3. #3
    Join Date
    May 2002
    Posts
    1,435

    Re: Template const & non-const versions

    It's not clear to me what your are trying to do, but maybe you should consider overloading functions with const versions:
    Code:
    int *Get()
    {
        return p_i;
    }
     
    const int *Get() const
    {
        return p_i;
    }
    If that's not what you need, try should how you would like to use the Test class even if it won't compile.

  4. #4
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,725

    Re: Template const & non-const versions

    The class is used as a functor for std::for_each in const & non-const variations of another class' function.
    The const function requires that the functor be defined with const members.

    What I want is not to have to write the functor twice, as shown below.
    Code:
    #include <algorithm>
    #include <vector>
    #include <iostream>
    
    using namespace std;
    
    // Non-const functor
    class Functor
    {
    public:
        Functor()
            : p_i(0)
        {
        }
    
        void operator()(int &i)
        {
            if (i == 10)
            {
                p_i = &i;
            }
        }
    
        int *Result()
        {
            return p_i;
        }
    
        int *p_i;
    };
    
    // Const functor
    class Const_Functor
    {
    public:
        Const_Functor()
            : p_i(0)
        {
        }
    
        void operator()(const int &i)
        {
            if (i == 10)
            {
                p_i = &i;
            }
        }
    
        const int *Result()
        {
            return p_i;
        }
    
        const int *p_i;
    };
    
    //**************************************
    struct Test
    {
        Test()
            : data(10, 0)
        {
            data[3] = 10;
        }
    
        // Non-const Find
        int *Find()
        {
            Functor f = for_each(data.begin(), data.end(), Functor());
    
            return f.Result();
        }
    
        // Const Find
        const int *Find() const
        {
            Const_Functor f = for_each(data.begin(), data.end(), Const_Functor());
    
            return f.Result();
        }
    
        // Const print
        void Print() const
        {
            // Look for 10.
            const int *p_i = Find();
    
            if (p_i != 0)
            {
                cout << *p_i;
            }
            else
            {
                cout << "Not found";
            }
        }
    
        vector<int> data;
    };
    
    //**************************************
    int main()
    {
        Test t;
    
        t.Print();
    }
    "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

  5. #5
    Join Date
    Oct 2008
    Posts
    1,163

    Re: Template const & non-const versions

    if you don't want to use boost, then you could write something like

    Code:
    template <typename T>
    struct DefaultTest { typedef T type; };
    
    template <typename T>
    struct ConstTest { typedef const T type; };
    
    template < template <typename T> class TestType = DefaultTest >
    class Test
    {
    public:
    	typedef typename TestType<int>::type ArgType;
    
    	void Set(ArgType &i)
    	{
    		p_i = &i;
    	}
    
    	ArgType *Get()
    	{
    		return p_i;
    	}
    
    private:
         ArgType *p_i;
    };
    
    Test<> test;
    Test<ConstTest> const_test;

  6. #6
    Join Date
    Jan 2006
    Location
    Belo Horizonte, Brazil
    Posts
    405

    Re: Template const & non-const versions

    Quote Originally Posted by JohnW@Wessex View Post
    The class is used as a functor for std::for_each in const & non-const variations of another class' function.
    I once had a similar problem to implement two versions of iterators: a const and a non-const one. If I remember correctly, I saw this idea at SGI's STL.

    Create a const traits and then model your class based on that level of indirection.

    Code:
    template <class value_t>
    struct const_traits
    {
      typedef value_t value_type;
      typedef const value_t* pointer;
      typedef const value_t& reference;
    };
    
    
    template <class value_t>
    struct non_const_traits
    {
      typedef value_t value_type;
      typedef value_t* pointer;
      typedef value_t& reference;
    };
    
    
    template <class constness_traits_t>  
    class functor
    {
      typedef typename constness_traits_t::value_type value_type;
      typedef typename constness_traits_t::pointer pointer;
      typedef typename constness_traits_t::reference reference;
    
      void operator()(reference i);
    
      /*... */
    
    };
    Last edited by ltcmelo; October 27th, 2009 at 01:00 PM.

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

    Re: Template const & non-const versions

    Some interesting ideas
    I'll have to give them some thought.
    "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
    Jul 2002
    Posts
    2,521

    Re: Template const & non-const versions

    It looks like your initial solution with two typedefs is the best one. If something can be solved by simple way, there is not need for complicated version.

    Code:
    template<class T>
    class Functor
    {
    public:
        Functor()
            : p_i(0)
        {
        }
    
        void operator()(T &i)
        {
            if (i == 10)
            {
                p_i = &i;
            }
        }
    
        T *Result()
        {
            return p_i;
        }
    
        T *p_i;
    };
    
    typedef Functor<int> NormalFunctor;
    typedef Functor<const int> ConstFunctor;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        int n = 0;
    
        NormalFunctor n1;
        ConstFunctor n2;
    
        n1(n);
        n2(n);
    
        return 0;
    }
    Notice that NormalFunctor and ConstFunctor look like STL iterator and const_iterator, pretty standard for a user.

    But if we want to make NormalFunctor and ConstFunctor typedefs not only for int type? Typedef cannot be templated, but there is solution with helper template:

    Code:
    template<class T>
    class Functor
    {
    public:
        Functor()
            : p_i(0)
        {
        }
    
        void operator()(T &i)
        {
            if (i == 10)
            {
                p_i = &i;
            }
        }
    
        T *Result()
        {
            return p_i;
        }
    
        T *p_i;
    };
    
    template<class T>
    struct FunctorType
    {
        typedef Functor<T> NormalFunctor;
        typedef Functor<const T> ConstFunctor;
    };
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        int n = 0;
    
        FunctorType<int>::NormalFunctor n1;
        FunctorType<int>::ConstFunctor n2;
    
        n1(n);
        n2(n);
    
        short k = 0;
    
        FunctorType<short>::NormalFunctor k1;
        FunctorType<short>::ConstFunctor k2;
    
        k1(k);
        k2(k);
    
    
        return 0;
    }

  9. #9
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,725

    Re: Template const & non-const versions

    Thanks for all the ideas guys.

    What I used in the end was like superbonzo's idea but makes use of the TR1 type traits classes.

    Code:
    #include <algorithm>
    #include <vector>
    #include <iostream>
    
    #include <type_traits>
    
    using namespace std;
    using namespace std::tr1;
    
    // Functor
    template<template<typename> class Traits>
    class Functor
    {
    public:
    
        typedef typename Traits<int>::type Type;
    
        Functor()
            : p_i(0)
        {
        }
    
        void operator()(Type &i)
        {
            if (i == 10)
            {
                p_i = &i;
            }
        }
    
        Type *Result() const
        {
            return p_i;
        }
    
        Type *p_i;
    };
    
    //**************************************
    struct Test
    {
        Test()
            : data(10, 0)
        {
            data[3] = 10;
        }
    
        // Non-const Find
        int *Find()
        {
            Functor<remove_const> f = for_each(data.begin(), data.end(), Functor<remove_const>());
    
            return f.Result();
        }
    
        // Const Find
        const int *Find() const
        {
            Functor<add_const> f = for_each(data.begin(), data.end(), Functor<add_const>());
    
            return f.Result();
        }
    
        // Const Print.
        void Print() const
        {
            // Look for 10.
            const int *p_i = Find();
    
            if (p_i != 0)
            {
                cout << *p_i << "\n";
            }
            else
            {
                cout << "Not found\n";
            }
        }
    
        // Non-const Change.
        void Change()
        {
            // Look for 10.
            int *p_i = Find();
    
            if (p_i != 0)
            {
                *p_i = 20;
                cout << "Changed to 20\n";
            }
            else
            {
                cout << "Not found\n";
            }
        }
    
        vector<int> data;
    };
    
    //**************************************
    int main()
    {
        Test t;
    
        t.Print();
        t.Change();
        t.Print();
    }
    "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

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

This is a CodeGuru survey question.


Featured


HTML5 Development Center