specialize template for eg vector< T >

S

stinos

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!
 
K

Kai-Uwe Bux

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
 
A

Alan Johnson

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.
 
A

Alan Johnson

Alan said:
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. :)
 
S

stinos

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)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top