Metafunctions
Metafunctions are used for getting types and constants at compile time.
Generic algorithms usually have to know certain types that correspond to their arguments: An algorithm
on strings may need to know which type of characters are stored in the string, or what kind of iterator can
be used to browse it. SeqAn uses Metafunctions (also known as "traits") for that purpose.
For example: Assuming that we define a string of amino acids:
Now lets define a function that exchanges the first two values in a string:
{
if (length(str) < 2) return;
AminoAcid temp = str[0];
str[0] = str[1];
str[1] = temp;
}
Since this function only works for instances of String<AminoAcid> , we could try to make it more general by making a template out of it:
void exchangeFirstValues(T & str)
{
if (length(str) < 2) return;
AminoAcid temp = str[0];
str[0] = str[1];
str[1] = temp;
}
Now the function works for all sequence types T that store AminoAcid objects,
but it will fail for other value types as soon as the variable temp cannot store str[0] anymore.
To overcome this problem, we must redefine temp in a way that it can store a value of the correct type.
The question is: "Given a arbitrary type T , what is the value type of T ?"
The metafunction Value anwers this question: "The value type of T is given by Value<T>::Type ."
Hence, the final version of our function exchangeFirstValues reads as follows:
void exchangeFirstValues(T & str)
{
if (length(str) < 2) return;
typename Value<T>::Type temp = str[0];
str[0] = str[1];
str[1] = temp;
}
We can view Value as a kind of "function" that takes T as an argument (in angle brackets) and returns the required value type of T .
In fact, Value is not implemented as a C++ function, but as a class template.
This class template is specialized for each sequence type T in a way that
the typedef Type provides the value type of T .
Unfortunately, the current C++ language standard does not allow to write simply "Value<T> temp; ", so we must select the return value by appending "::Type ".
The leading "typename " becomes necessary since Value<T>::Type is a type that depends on a template parameter of the surrounding function template.
The metafunction Value is a type metafunction, i.e. it is used to determine a type.
Type metafunctions have the form:
The name of the metafunction | |
Arguments (types or constants) | |
The resulting type |
The keyword typename must be stated if one of the arguments T1 , T2 , ..., TN is or uses a template parameter.
Example: The following piece of code uses the metafunction Iterator to determine an iterator type for a string class:
Iterator<String<char> >::Type it = begin(str);
while (! atEnd(it, str))
{
::std::cout << *it;
++it;
}
Metafunctions can also be used to determine constant values at compile time. The general form of value metafunctions is:
The name of the metafunction | |
Arguments (types or constants) | |
The resulting constant value |
Example:The following function prints the length of a fixed sized string using the value metafunction LENGTH:
void printLenOfFixedSizeString(T const &)
{
::std::cout << LENGTH<T>::VALUE;
}
String<char, Array<100> > my_str;
printLenOfFixedSizeString(my_str);
SeqAn - Sequence Analysis Library - www.seqan.de