specialize template for eg vector< T >

Discussion in 'C++' started by stinos@skynet.be, Jan 27, 2007.

  1. Guest

    Hi All!

    suppose a class having a function for outputting data somehow,

    class X
    {
    template< class tType >
    void Output( const tType& arg )
    {
    //default ToString handles integers/doubles
    myOutput( ToString( arg ) );
    }

    //String itself can be outputted directly
    template<>
    void Output< String >( const String& arg )
    {
    myOutput( arg );
    }

    void myOutput( const String& s );
    };

    now I'd like to add functionality in some way, be it through
    specialization or overloading or just anything, so that when a
    std::vector< tType > is passed in, it does something like

    void Output( const vector< tType >& arg )
    {
    const size_t nItems = arg.size();
    for( size_t i = ; 0 i < nItems ; ++i )
    Output( arg[ i ] );
    }

    Any ideas on how to achieve this? Or more general, how to find out
    whether a type passed in is a plain type, or a something< type>.
    I checked the boost libs a bit, because they seem to rely on template
    stuff a lot, but couldn't find an answer immedeately..

    Thanks in advance!
     
    , Jan 27, 2007
    #1
    1. Advertising

  2. Kai-Uwe Bux Guest

    wrote:

    > Hi All!
    >
    > suppose a class having a function for outputting data somehow,
    >
    > class X
    > {
    > template< class tType >
    > void Output( const tType& arg )
    > {
    > //default ToString handles integers/doubles
    > myOutput( ToString( arg ) );
    > }
    >
    > //String itself can be outputted directly
    > template<>
    > void Output< String >( const String& arg )
    > {
    > myOutput( arg );
    > }
    >
    > void myOutput( const String& s );
    > };
    >
    > now I'd like to add functionality in some way, be it through
    > specialization or overloading or just anything, so that when a
    > std::vector< tType > is passed in, it does something like
    >
    > void Output( const vector< tType >& arg )
    > {
    > const size_t nItems = arg.size();
    > for( size_t i = ; 0 i < nItems ; ++i )
    > Output( arg[ i ] );
    > }
    >
    > Any ideas on how to achieve this? Or more general, how to find out
    > whether a type passed in is a plain type, or a something< type>.


    What about:

    #include <vector>
    #include <iostream>

    template < typename T >
    void out ( T const & t ) {
    std::cout << "generic out function called.\n";
    }

    template < typename T, typename A >
    void out ( std::vector<T,A> const & v ) {
    std::cout << "std::vector specialization called.\n";
    }

    int main ( void ) {
    std::vector< std::vector< int > > ivv;
    int g;
    out( ivv );
    out( g );
    }


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Jan 27, 2007
    #2
    1. Advertising

  3. Alan Johnson Guest

    wrote:
    > Hi All!
    >
    > suppose a class having a function for outputting data somehow,
    >
    > class X
    > {
    > template< class tType >
    > void Output( const tType& arg )
    > {
    > //default ToString handles integers/doubles
    > myOutput( ToString( arg ) );
    > }
    >
    > //String itself can be outputted directly
    > template<>
    > void Output< String >( const String& arg )
    > {
    > myOutput( arg );
    > }
    >
    > void myOutput( const String& s );
    > };
    >
    > now I'd like to add functionality in some way, be it through
    > specialization or overloading or just anything, so that when a
    > std::vector< tType > is passed in, it does something like
    >
    > void Output( const vector< tType >& arg )
    > {
    > const size_t nItems = arg.size();
    > for( size_t i = ; 0 i < nItems ; ++i )
    > Output( arg[ i ] );
    > }
    >
    > Any ideas on how to achieve this? Or more general, how to find out
    > whether a type passed in is a plain type, or a something< type>.
    > I checked the boost libs a bit, because they seem to rely on template
    > stuff a lot, but couldn't find an answer immedeately..
    >
    > Thanks in advance!
    >


    Firstly, please try your best to post complete examples. See:
    http://www.parashift.com/c -faq-lite/how-to-post.html#faq-5.8

    In example code I've provided reasonable implementations for the
    functions you've left out.

    Firstly, your specialization for String won't compile in at least one
    compile (g++), because it requires all explicit specializations to be at
    namespace scope. I'm a bit confused about whether this is standard
    behavior or a g++ bug, but in any case it is only the beginning of the
    headache.

    What you are trying to do is called "partial template specialization".
    Now the syntax that would be natural is as follows:

    // WARNING: Not valid C++.
    template <class U>
    void Output< std::vector<U> >(const std::vector<U> & arg)
    {
    // whatever
    }

    However, the standard only allows class templates (not functions or
    member functions) to be partially specialized. What is the reason for
    this restriction? As far as I can tell there is no good reason. That's
    just the way it is.

    So instead we'll use a helper class (a struct actually) with a static
    member function to do the real work. We'll partially specialize the
    class. Then we'll have our template member function forward the call to
    the correct specialization of the helper class. Code can explain it
    better than words:

    #include <iostream>
    #include <vector>
    #include <string>
    #include <sstream>

    template <class T>
    std::string ToString(T arg)
    {
    std::stringstream ss ;
    ss << arg ;
    return ss.str() ;
    }

    class X
    {
    private:

    template <class T>
    struct Outputter
    {
    static void Output(const X & x, const T & arg)
    {
    std::cout << "<default> " ;
    x.myOutput(ToString(arg)) ;
    }
    } ;

    public:
    void myOutput(const std::string & s) const
    {
    std::cout << "myOutput: " << s << std::endl ;
    }

    template <class T> void Output(const T & arg) const
    {
    Outputter<T>::Output(*this, arg) ;
    }
    } ;

    // Defined at namespace scope because g++ won't let explicit
    // specializations exist elsewhere.
    template <>
    struct X::Outputter<std::string>
    {
    static void Output(const X & x, const std::string & arg)
    {
    std::cout << "<string> " ;
    x.myOutput(arg) ;
    }
    } ;

    // Partial template specialization.
    // Defined at namespace scope because g++ won't let explicit
    // specializations exist elsewhere.
    template <class U>
    struct X::Outputter< std::vector<U> >
    {
    static void Output(const X & x, const std::vector<U> & arg)
    {
    std::cout << "<vector> " << std::endl ;
    for (std::size_t i = 0; i < arg.size(); ++i)
    x.Output(arg) ;
    }
    } ;

    int main()
    {
    X x ;
    x.Output(5) ;
    x.Output(std::string("hello world")) ;

    std::vector<std::string> v ;
    v.push_back("string1") ;
    v.push_back("string2") ;
    x.Output(v) ;
    }


    And there you go.

    --
    Alan Johnson
     
    Alan Johnson, Jan 27, 2007
    #3
  4. Alan Johnson Guest

    Alan Johnson wrote:
    > wrote:
    >> Hi All!
    >>
    >> suppose a class having a function for outputting data somehow,
    >>
    >> class X
    >> {
    >> template< class tType >
    >> void Output( const tType& arg )
    >> {
    >> //default ToString handles integers/doubles
    >> myOutput( ToString( arg ) );
    >> }
    >>
    >> //String itself can be outputted directly
    >> template<>
    >> void Output< String >( const String& arg )
    >> {
    >> myOutput( arg );
    >> }
    >>
    >> void myOutput( const String& s );
    >> };
    >>
    >> now I'd like to add functionality in some way, be it through
    >> specialization or overloading or just anything, so that when a
    >> std::vector< tType > is passed in, it does something like
    >>
    >> void Output( const vector< tType >& arg )
    >> {
    >> const size_t nItems = arg.size();
    >> for( size_t i = ; 0 i < nItems ; ++i )
    >> Output( arg[ i ] );
    >> }
    >>
    >> Any ideas on how to achieve this? Or more general, how to find out
    >> whether a type passed in is a plain type, or a something< type>.
    >> I checked the boost libs a bit, because they seem to rely on template
    >> stuff a lot, but couldn't find an answer immedeately..
    >>
    >> Thanks in advance!
    >>

    > [snip]


    Or you can dispense with all the complexity of my solution and use the
    much simpler solution of function overloading as Kai-Uwe Bux suggested. :)

    --
    Alan Johnson
     
    Alan Johnson, Jan 27, 2007
    #4
  5. Guest

    mm weird, I thought I already replied saturday but I don't dee my
    post.. must have clicked the wrong button or so..

    @both repliers: thanks a lot, you gave the exact solution I was
    looking for..

    >Firstly, your specialization for String won't compile in at least one
    >compile (g++), because it requires all explicit specializations to be at
    >namespace scope. I'm a bit confused about whether this is standard
    >behavior or a g++ bug, but in any case it is only the beginning of the
    >headache.


    I'm aware of that.. not sure if the standard means "specialize right
    in namespace scope" (g++), or if it's more like "specialize anywhere
    in namespace scope, so within a class that's in that scope is fine
    too" (cl)
     
    , Jan 31, 2007
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Old Wolf
    Replies:
    4
    Views:
    397
    Victor Bazarov
    Apr 8, 2005
  2. mrstephengross
    Replies:
    1
    Views:
    289
    Victor Bazarov
    Aug 2, 2005
  3. sebastian
    Replies:
    1
    Views:
    284
  4. Replies:
    1
    Views:
    363
    Victor Bazarov
    Feb 17, 2006
  5. toton
    Replies:
    3
    Views:
    391
    Victor Bazarov
    Jan 25, 2007
Loading...

Share This Page