traits class (whats it all about?)

B

Bit Byte

Can't seem to get my head around the point of a trait class - no matter
how many times I read up on it - why not simply use functors or function
pointers ?

Anyone care to explain this in a simple straightforward way that a
simple guy from "Missourah" can understand ?
 
D

Deniel Rose'

perhaps due to trait timetable personally set up to feed itself,
nothing that really matters much to the heir !
well, pretty off-topical explanation though but I'd rather think of a
modern model for the shelter at millions of dollars after all rather
than turning myself to be knittie-pickie over what a trait is dealing
with fAnct0rs, :p
 
B

Bit Byte

Deniel said:
perhaps due to trait timetable personally set up to feed itself,
nothing that really matters much to the heir !
well, pretty off-topical explanation though but I'd rather think of a
modern model for the shelter at millions of dollars after all rather
than turning myself to be knittie-pickie over what a trait is dealing
with fAnct0rs, :p

Huh ?
 
S

Salt_Peter

Bit said:
Can't seem to get my head around the point of a trait class - no matter
how many times I read up on it - why not simply use functors or function
pointers ?

Anyone care to explain this in a simple straightforward way that a
simple guy from "Missourah" can understand ?

Sure you can use functions/functors. But why have to rewrite them if
you can classify templates by the class traits? Instead of specializing
one template specificly for one type, classify reusable templates on
traits.

Consider following the discussion at:
http://www.boost.org/doc/html/boost_typetraits.html

And consult the examples there as well.
 
D

dasjotre

Bit said:
Can't seem to get my head around the point of a trait class - no matter
how many times I read up on it - why not simply use functors or function
pointers ?

Anyone care to explain this in a simple straightforward way that a
simple guy from "Missourah" can understand ?

"Think of a trait as a small object whose main purpose
is to carry information used by another object or
algorithm to determine "policy" or "implementation details"."
[Bjarne Stroustrup]

a simple example would be copy algorithm
template<class InIt, class OutIt>
OutIt copy(InIt from, InIt to, OutIt dest)
{
while(from != to)
{
*dest = *from;
++from, ++dest;
}
return dest;
}

Now consider a situation like this
char som_str[100];
....
char dest_str[100];
you could use the above function
copy(som_str, som_str+100, dest_str);

but the best way would be to simply
copy memory

so you write another version of copy

template<class InIt, class OutIt>
OutIt copy(InIt from, InIt to, OutIt dest)
{
memcpy(dest, from, to-from);
return dest+(to-from);
}

Now you need some way to tell the compiler
which version to use

so you've come to a situation where if
InIt and OutIt are pointer types and they
point to objects of POD type you want to
use the second version. But if they are
something else you need the first version.

So you write a traits class by combining
the type traits (these are from boost)
template<class InIt, class OutIt>
struct memcopyable
{
// so value will be compile time constant
// which will be true if InIt and OutIt satisfy
// the memcopyable requirement
enum { value =
boost::is_pointer<InIt>::value &&
boost::is_pod<boost::remove_pointer<InIt>::type >::value &&
boost::is_pointer<OutIt>::value &&
boost::is_pod<boost::remove_pointer<OutIt>::type >::value };
};


Now provide two implementations
One for memcopyable, and one for others

template<bool memcopyable>
struct copy_implementation;

template<>
struct copy_implementation<false>
{
template<class InIt, class OutIt>
static OutIt copy(InIt from, InIt to, OutIt dest)
{
while(from != to)
{
*dest = *from;
++from, ++dest;
}
return dest;
}
};

template<>
struct copy_implementation<true>
{
template<class InIt, class OutIt>
static OutIt copy(InIt from, InIt to, OutIt dest)
{
memcpy(dest, from, to-from);
return dest+(to-from);
}
};

template<class InIt, class OutIt>
OutIt copy (InIt from, InIt to, OutIt dest)
{
return copy_implementation<memcopyable<InIt,
OutIt>::value>::copy(from, to, dest);
}

So when you call it as above

char som_str[100];
....
char dest_str[100];
copy(som_str, som_str+100, dest_str);

the compiler will magically select the
memcopy version
 
B

benben

Bit said:
Can't seem to get my head around the point of a trait class - no matter
how many times I read up on it - why not simply use functors or function
pointers ?

Anyone care to explain this in a simple straightforward way that a
simple guy from "Missourah" can understand ?

Let's say you need to sum a range of numbers, and you start by:

template <typename Itr>
RETVAL_T sum_up(Itr begin, Itr end)
{
RETVAL_T sum = 0;

for (Itr i = begin; i != end; ++i)
{
sum += *i;
}

return sum;
}

All is good except you don't know what RETVAL_T is. You are only given
the iterator type and that can be anything. You need to know what value
type corresponds to that iterator type.

No problem, use traits. A traits class is what you relate some
compile-time information with a specific type. The
std::iterator_traits<> template relates value type with a specific
iterator type, so we do:

template <typename Itr>
typename std::iterator_traits<Itr>::value_type // RETVAL_T
sum_up(Itr begin, Itr end)
{
typename std::iterator_traits<Itr>::value_type sum = 0;

for (Itr i = begin; i != end; ++i)
{
sum += *i;
}

return sum;
}

Hope this is simple enough for you to grasp!

Regards,
Ben
 
D

Daniel T.

Bit Byte said:
Can't seem to get my head around the point of a trait class - no matter
how many times I read up on it - why not simply use functors or function
pointers ?

Anyone care to explain this in a simple straightforward way that a
simple guy from "Missourah" can understand ?

Just in case the earlier explanations didn't help...

A traits class is a way to add compile time information to a class
without actually putting it in the class. The reason this is useful is
because with a traits class, one can add compile time information to
intrinsic types (like int, and double,) and types you didn't write and
can't change (like string, list and classes from some vendor.)

It's just that simple.
 
N

Noah Roberts

Salt_Peter said:
Sure you can use functions/functors.

Actually, you can't. Many uses of traits, in fact the primary use of
them, simply cannot be provided by functions or functors. Take for
instance code like this:

template < typename Iter_t >
void f(Iter_t)
{
std::iterator_traits<Iter_t>::value_type x;
x = *Iter_t;

....
}

How are you going to provide the functionality needed to declare x
using a function or functor?

Since C++ has no meta objects (during runtime) you simply can't provide
that type of functionality in a generic manner using functions or
functors. It's got to be a metafunction or trait blob.

And that should answer the OP's question.
 
K

kwikius

Bit said:
Can't seem to get my head around the point of a trait class - no matter
how many times I read up on it - why not simply use functors or function
pointers ?

Anyone care to explain this in a simple straightforward way that a
simple guy from "Missourah" can understand ?

Below is another example of how traits classes can be used and why you
might want to. Also see:

http://www.boost.org/doc/html/boost_typetraits.html which has an
is_pointer type_trait.
std::char_traits in <string> and std::numeric_limits in <limits>
for other examples of commonly used traits classes. Note that recent
designs tend to favour one traits per traits class like the is_pointer
example rather than putting many in one class like char_traits and
numeric_limits.

For more advanced uses and 'metaprogramming" see

http://www.boost.org/libs/mpl/doc/index.html

and

http://spirit.sourceforge.net/dl_more/fusion_v2/libs/fusion/doc/html/index.html


//----------

#include <iostream>

// traits class providing info whether T is a pointer
// preferable to use boost or std::tr1 version in practise
template <typename T>
struct is_pointer{
static const bool value = false;
};

template <typename T>
struct is_pointer<T*> {
static const bool value = true;
};

//-----------------------

// a functor class specialised (below) on whether T is a pointer
// the default argument is never meant to be used by the user
// and would usually be hidden but exposed here to show the workings.

template <typename T, bool Condition = is_pointer<T>::value>
struct static_pointer_info_about;

// the specialisations
template <typename T>
struct static_pointer_info_about<T, true>{
void operator()()const
{
std::cout << typeid(T).name() << " is a pointer\n";
}
};

template <typename T>
struct static_pointer_info_about<T, false>{
void operator()()const
{
std::cout << typeid(T).name() << " is not a pointer\n";
}
};

// a function that wraps the low level stuff a bit
template <typename T>
void pointer_info_about( T t)
{
static_pointer_info_about<T> f;
f();
}

// and use ..
int main()
{
const char* hello = "hello"; // hello is a pointer
int n = 1; // int is not

pointer_info_about(hello);
pointer_info_about(n);

}

regards
Andy Little
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top