CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Traits class question

    I have a function which I'd like to take a generic 2D array of some sort (T**, multi_array, or anything else that can be accessed in a 2D manner). I need to pull out the underlying element type.

    It seems to me that a traits class is the right way to go, and that one probably exists which will work fine, but I don't know enough about traits classes to be sure.

    For instance, I was considering iterator_traits<iterator_traits<Arr2DType>::value_type>::value_type, but the problem is that while this should work for a T** directly, I'd need to call begin() on a multi_array to get the appropriate iterator. So I thought about boost::begin(), but that doesn't say what it does on simple pointers, only fixed-size arrays.

    Any suggestions?

    Another option I was considering aside from traits classes was decltype(data[0][0]). Since this could be a reference type, I thought perhaps boost::remove_const<boost::remove_reference<decltype<data[0][0]>>>::type. Haven't tested that though. (And I may want to generalize element lookup so that I can support types which use a 2-element operator() as well.)

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

    Re: Traits class question

    How can you write a function that generically takes either a container that is size aware, or a T** that is size un-aware?

    If the algorithm doesn't need to know the array dimensions, I'd just write my function std-like and take a "first" and "last" argument.
    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.

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

    Re: Traits class question

    Quote Originally Posted by Lindley View Post
    For instance, I was considering iterator_traits<iterator_traits<Arr2DType>::value_type>::value_type, but the problem is that while this should work for a T** directly, I'd need to call begin() on a multi_array to get the appropriate iterator. So I thought about boost::begin(), but that doesn't say what it does on simple pointers, only fixed-size arrays.

    Any suggestions?
    Why not specialise your class for pointers?

  4. #4
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Traits class question

    Quote Originally Posted by monarch_dodra View Post
    How can you write a function that generically takes either a container that is size aware, or a T** that is size un-aware?
    Well, there are additional x,y,w,h arguments so that a sub-rectangle of the entire image may be processed.

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

    Re: Traits class question

    In that case, I'd just make two specialized interface functions, that forward the required types.

    I think this keeps the code simple, and doesn't create any executable bloat (the same amount of code is compiled, and the forwarder functions are probably entirely elided, since empty)

    Code:
    template <typename T, typename Value>
    void foo_impl(T& container)
    {
        std::cout << "Forwarded" << std::endl;
    }
    
    //T is a 2D structure of some kind
    template <typename T>
    void foo(T& container)
    {
        typedef typename std::iterator_traits<typename T::iterator>::value_type Value;
        std::cout << "Container" << std::endl;
        foo_impl<T, Value>(container);
    }
    
    //T is a 2D array
    template <typename T>
    void foo(T** array2D)
    {
        std::cout << "2D" << std::endl;
        foo_impl<T**, T>(array2D);
    }
    
    int main(int argc, char *argv[])
    {
        int** pp;
        std::vector<int> v;
        foo(pp);
        foo(v);
        return 0;
    }
    Last edited by monarch_dodra; June 1st, 2010 at 11:38 AM.
    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.

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

    Re: Traits class question

    Quote Originally Posted by Lindley View Post
    It seems to me that a traits class is the right way to go, and that one probably exists which will work fine, but I don't know enough about traits classes to be sure.

    For instance, I was considering iterator_traits<iterator_traits<Arr2DType>::value_type>::value_type, but the problem is that while this should work for a T** directly, I'd need to call begin() on a multi_array to get the appropriate iterator. So I thought about boost::begin(), but that doesn't say what it does on simple pointers, only fixed-size arrays.

    Any suggestions?
    A traits class should define all the functionality and information you need in order to use the Arr2DType. So using iterator traits only makes sense if you require Arr2DType to support iterators. Even then, I wouldn't use them, because they have a different purpose. Consider what happens if someone wants to provide a vector<vector<T> > as matrix type. The value_type in the iterator traits will be vector<T>, but that's actually not what you want.

    So I would opt to develop a custom traits class that contains all the functionality your algorithm needs.

    If you are interested in some reading material, The Boost Graph Library gives a great explanation of how to design traits classes.
    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

  7. #7
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Traits class question

    this could work ( but I've not tested it ):

    Code:
    #include <vector>
    #include <boost/mpl/has_xxx.hpp>
    
    BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF( has_value_type, value_type, false )
    
    template <class T, bool rescurse = has_value_type<T>::value >
    struct get_value_type
    {
    	typedef typename get_value_type< typename T::value_type >::type type;
    };
    
    template <class T>
    struct get_value_type<T,false>
    {
    	typedef T type;
    };
    
    typedef get_value_type< std::vector< std::vector<int> > >::type should_be_an_int;
    then, you can specialize get_value_type for T** or any other type you like...

  8. #8
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Traits class question

    If I end up having to specialize a completely new traits class that's fine. I was just hoping that something in Boost or the STL would provide an appropriate traits class already. Oh well.

Posting Permissions

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





Click Here to Expand Forum to Full Width

Featured