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