template<typename… Types> // declare liststruct
Count; // walking template
template<typename T, typename… Rest> // walk list
struct Count<T, Rest…>
{
const static int value = Count<Rest…>::value +1;
};
template<> struct Count<> // recognize end of
{ // list
const static int value = 0;
};
auto count1 = Count<int, double, char>::value; // count1 = 3
auto count2 = Count<>::value; // count2 = 0
Count purely an exercise; C++0x’s sizeof…does the same thing:
template<typename… Types>
struct VerifyCount
{
static_assert(Count<Types…>::value == sizeof…(Types),
"Count<T>::value != sizeof…(T)");
};
Unpack (…) and sizeof…only two operations for parameter packs.void print() { std::cout << '\n'; }; // print 0 objects
template<typename T, // type of 1st object
typename... TRest> // types of the rest
void print( const T& obj, // 1st object
const TRest&... rest) // the rest of them
{
std::cout << obj << " "; // print 1st object
print(rest...); // print the rest
}
double p = 3.14;
std::string s("Vari");
print(-22, p, &p, s, "adic"); // -22 3.14 0x22ff40 Vari adic
Unpacking Patterns:
Unpacking uses the pattern of the expression being unpacked:
template<class T, class... Args>
shared_ptr<T> // add “&&” to each
make_shared(Args&&... params); // unpacked elem.
template<typename T, typename... TRest> // add “const” and
void print(const T& obj, const TRest&... rest) // “&” to each
{
std::cout << obj << " ";
print(rest...); // add nothing to
} // each elem’s name
Call to print expands to:print(rest1, rest2, ..., restn);
The ellipsis is always at the end of the pattern.template<typename T> // return a normalized
T normalize(T&& obj); // copy of obj
template<typename F, typename… PTypes>
void normalizedCall( F func,
PTypes&&… params) // as before
{
func(normalize(params)…); // call normalize on
} // each unpacked elem
Call to func expands to:func(normalize(params1), normalize(params2), ..., normalize(paramsn));
template <typename... Ts>
class C
{
: : :
};
template <typename... Ts>
void fun(const Ts&... vs)
{
: : :
}
Ts is not a type; vs is not a value!
typedef Ts MyList; // error!
Ts var; // error!
auto copy = vs; // error!
• Ts is an alias for a list of types
• vs is an alias for a list of values
• Either list may be potentially empty
• Both obey only specific actions
• Apply sizeof... to it, this will return how many class type in Ts, e.g , number of Arguments
size_t items = sizeof...(Ts); // or vs
• Expand backtemplate <typename... Ts>
void fun(Ts&&... vs) {
gun(3.14, std::forward<Ts>(vs)..., 6.28);
}
Expansion rules:
Be aware! ... is not , operator!
But expanded to a argument list!
http://stackoverflow.com/a/16012355
Thus:
#include <iostream>
using namespace std;
template<typename... T>
void layer(T... t)
{}
int run(int a)
{
return a;
}
template<int... i>
void fun()
{
/*run(i)...; // This won't work!*/
layer(run(i)...); // This works!
}
int main()
{
fun<1,2,3>();
}
• Initializer lists
any a[] = { vs... };
• Base specifierstemplate <typename... Ts>
struct C : Ts... {};
template <typename... Ts>
struct D : Box<ts>... { : : : };
• Member initializer lists// Inside struct D
template <typename... Us>
D(Us... vs) : Box<ts>(vs)... {}
• Template argument lists
std::map<Ts...> m;
• Exception specifications◦ On second thought, scratch that
• Attribute lists
struct [[ Ts... ]] IAmFromTheFuture {};
• Capture liststemplate <class... Ts> void fun(Ts... vs) {
auto g = [&vs...] { return gun(vs...); }
g();
}
CRAZY!!
Multiple expansions
• Expansion proceeds outwards
• These are different expansions!
template <class... Ts> void fun(Ts... vs) {
gun(A<Ts...>::hun(vs)...);
gun(A<Ts...>::hun(vs...));
gun(A<Ts>::hun(vs)...);
}
template <
typename T,
template <
template<class...> class... Policies
>
>
class ICantBelieveItsNotButter;
---------------
How to use variadics?
• Pattern matching!
template <class T1, class T2>
bool isOneOf(T1&& a, T2&& b) {
return a == b;
}
template <class T1, class T2, class... Ts>
bool isOneOf(T1&& a, T2&& b, Ts&&... vs) {
return a == b || isOneOf(a, vs...);
}
assert(isOneOf(1, 2, 3.5, 4, 1, 2));
template <class T>
typename enable_if<is_integral<T>::value, long>::type
normalizeArg(T arg) { return arg; }
template <class T> typename
enable_if<is_floating_point<T>::value, double>::type
normalizeArg(T arg) { return arg; }
template <class T>
typename enable_if<is_pointer<T>::value, T>::type
normalizeArg(T arg) { return arg; }
const char* normalizeArg(const string& arg) {
return arg.c_str();
}
// Not really safe yet
template <typename... Ts>
int safe_printf(const char * f,
const Ts&... ts) {
return printf(f, normalizeArg(ts)...);
}
void check_printf(const char * f) {
for (; *f; ++f) {
if (*f != ’%’ || *++f == ’%’) continue;
throw Exc("Bad format");
}
}
template <class T, typename... Ts>
void check_printf(const char * f, const T& t,
const Ts&... ts) {
for (; *f; ++f) {
if (*f != ’%’ || *++f == ’%’) continue;
switch (*f) {
default: throw Exc("Invalid format char: %", *f);
case ’f’: case ’g’:
ENFORCE(is_floating_point<T>::value);
break;
case ’s’: . . .
}
return check_printf(++f, ts...); // AHA!!!
}
throw Exc("Too few format specifiers.");
}
template <typename... Ts>
int safe_printf(const char * f,
const Ts&... ts) {
check_printf(f, normalizeArg(ts)...);
return printf(f, normalizeArg(ts)...);
}
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.