mirror of
https://gitlab.com/fbb-git/cppannotations
synced 2024-11-18 10:06:54 +01:00
e6536f5feb
git-svn-id: https://cppannotations.svn.sourceforge.net/svnroot/cppannotations/trunk@160 f6dd340e-d3f9-0310-b409-bdd246841980
104 lines
4.1 KiB
Text
104 lines
4.1 KiB
Text
Although em(class) templates may be partially specialized, em(function)
|
|
templates may not. At times that can be annoying. Assume a function template
|
|
is available implementing a certain unary operator that could be used with the
|
|
tt(transform) (cf. section ref(TRANSFORM)) generic algorithm:
|
|
verb(
|
|
template <typename Return, typename Argument>
|
|
Return chop(Argument const &arg)
|
|
{
|
|
return Return(arg);
|
|
}
|
|
)
|
|
Furthermore assume that if tt(Return) is tt(std::string) then the
|
|
specified implementation should not be used. Rather, with tt(std::string) a
|
|
second argument tt(1) should always be provided (e.g., if tt(Argument) is a
|
|
bf(C++) string, a tt(std::string) is returned holding a copy of the function's
|
|
argument, except for the argument's first character, which is chopped off).
|
|
|
|
Since tt(chop()) is a function, it is not possible to use a
|
|
partial specialization. So it is not possible to specialize for
|
|
tt(std::string) as attempted in the following erroneous implementation:
|
|
verb(
|
|
template <typename Argument>
|
|
std::string chop<std::string, Argument>(Argument const &arg)
|
|
{
|
|
return string(arg, 1);
|
|
}
|
|
)
|
|
it em(is) possible to use overloading, though. Instead of using partial
|
|
specializations em(overloaded function templates) could be designed:
|
|
verb(
|
|
template <typename Return, typename Argument>
|
|
Return chop(Argument const &arg, Argument )
|
|
{
|
|
return Return(arg);
|
|
}
|
|
|
|
template <typename Argument>
|
|
std::string chop(Argument const &arg, std::string )
|
|
{
|
|
return string(arg, 1);
|
|
}
|
|
)
|
|
This way it em(is) possible to distinguish the two cases, but at the
|
|
expense of a more complex function call (e.g., maybe requiring the use of the
|
|
ti(bind2nd()) binder (cf. section ref(FUNADAPT))
|
|
to bind the second argument to a fixed value) as well as the need to
|
|
provide a (possibly expensive to construct) dummy argument to allow the
|
|
compiler to choose among the two overloaded function templates.
|
|
|
|
Alternatively, overloaded versions em(could) use the tt(IntType) template
|
|
(cf. section ref(INTTYPE)) to select the proper overloaded version. E.g.,
|
|
tt(IntType<0>) could be defined as the type of the second argument of the
|
|
first overloaded tt(chop()) function, and tt(IntType<1>) could be used for the
|
|
second overloaded function. From the point of view of program efficiency this
|
|
is an attractive option, as the provided tt(IntType) objects are extremely
|
|
lightweight: they contain no data at all. But there's also an obvious
|
|
disadvantage: there is no intuitively clear association between on the
|
|
one hand the tt(int) value used and on the other hand the intended type.
|
|
|
|
In situations like these it is more attractive to use another lightweight
|
|
solution. Instead of using an arbitrary int-to-type association, an
|
|
intuitively clear and automatic type-to-type association is used. The
|
|
tt(struct TypeType) is a lightweight type wrapper, much like tt(IntType) is a
|
|
lightweight wrapper around an tt(int). Here is its definition:
|
|
verb(
|
|
template <typename T>
|
|
struct TypeType
|
|
{
|
|
typedef T Type;
|
|
};
|
|
)
|
|
This too is a lightweight type as it doesn't have any data fields
|
|
either. tt(TypeType) allows us to use a natural type association for
|
|
tt(chop())'s second argument. E.g, the overloaded functions can now be defined
|
|
as follows:
|
|
verb(
|
|
template <typename Return, typename Argument>
|
|
Return chop(Argument const &arg, TypeType<Argument> )
|
|
{
|
|
return Return(arg);
|
|
}
|
|
|
|
template <typename Argument>
|
|
std::string chop(Argument const &arg, TypeType<std::string> )
|
|
{
|
|
return std::string(arg, 1);
|
|
}
|
|
)
|
|
|
|
Using the above implementations any type can be specified for
|
|
tt(Result). If it happens to be a tt(std::string) the correct overloaded
|
|
version is automatically selected. E.g.,
|
|
verb(
|
|
template <typename Result>
|
|
Result chopper(char const *txt)
|
|
{
|
|
return chop(std::string(txt), TypeType<Result>());
|
|
}
|
|
)
|
|
Using tt(chopper()), the following statement will produce the text
|
|
`tt(ello world)':
|
|
verb(
|
|
cout << chopper<string>("hello world") << endl;
|
|
)
|