int x = "string"; // Errore!
template <typename T> struct A {};
A<int> aInt;
A<double> aDouble;
// ...
template <int N> struct B {};
B<0> bZero;
B<1> bOne;
template <typename T>
T add(const T & lhs, const T & rhs) {
return lhs + rhs;
}
// ...
auto x = add(5, 6);
auto y = add(std::string("a"), std::string("b"));
template <typename T>
struct A {
void operator() const {
std::cout << "Classe generica\n";
}
};
template <>
struct A<int> {
void operator() const {
std::cout << "Classe specializzata\n";
}
};
template <typename T>
struct A {
void operator() const {
std::cout << "Classe generica\n";
}
};
template <>
struct A<int> {
void operator() const {
std::cout << "Classe specializzata\n";
}
};
// ...
A<double>()(); // Scrive 'Classe generica'
A<int>()(); // Scrive 'Classe specializzata'
#include <iostream>
int main() {
int i = 0;
if (i == 0)
std::cout << "\"i\" is equal to zero.\n";
else
std::cout << "\"i\" is not equal to zero.\n";
return 0;
}
// SINTASSI
template<typename T> | template <int N>
struct A {}; | struct A {};
|
template <> | template <>
struct A<int> {}; | struct A<100> {};
#include <iostream>
int main() {
char x = 'c', y = 'd';
if (x == 'a')
std::cout << "\"x\" is equal to 'a'.\n";
else if (x == 'b' && y == 'd')
std::cout << "\"x\" is 'b' and \"y\" is 'd'.\n";
else
std::cout << "Values unknown.\n";
return 0;
}
// SINTASSI
template<typename T> | template <int N>
struct A {}; | struct A {};
|
template <> | template <>
struct A<int> {}; | struct A<100> {};
#include <iostream>
struct A { static constexpr int x = 0; };
struct B { static constexpr double y = 1; };
// Sconosciuta a priori
struct C { static constexpr double y = 0; };
template <typename T>
struct Printer {
void operator()() const { std::cout << T::x << '\n'; }
};
template <>
struct Printer<B> {
void operator()() const { std::cout << T::y << '\n'; }
};
int main() {
Printer<C>()(); // Errore di compilazione! x is not a member of C!
return 0;
};
#include <iostream>
struct A { static constexpr int x = 3; };
struct B { static constexpr int y = 3; };
template <typename T, typename Check = const int>
// template <typename T, typename Check>
struct Printer {
void operator()() const {
std::cout << "Questo tipo non ha il membro 'x'.\n";
}
};
template <typename T>
struct Printer<T, decltype(T::x)> {
void operator()() const {
std::cout << "Il membro 'x' di questa classe vale: " << T::x << '\n';
}
};
// ...
Printer<A>()();
Printer<B>()();
// Dove mettere gli "errori" nelle classi
template <typename T>
struct ClassName;
template <>
struct ClassName<int>;
// E nelle funzioni
template <typename R, typename T>
R foo(T);
struct A {
void foo();
};
struct B {
};
// Se il tipo ha un metodo foo()
// che ritorna void, stampa "FOO!"
// Altrimenti stampa "UNFOO'd!"
// SINTASSI
template<typename T, typename Check = /* some type */>
struct S;
template<typename T>
struct S<T, decltype(/*something*/)>;
struct A {
int foo();
};
struct B {
void foo();
};
struct C {};
// Se il tipo ha un metodo foo() *INDIPENDENTEMENTE
// DAL VALORE DI RITORNO*, allora stampa "ALL FOO!"
// Altrimenti stampa "UNFOO'd!"
// SINTASSI
template<typename T, typename Check = /* some type */>
struct S;
template<typename T>
struct S<T, decltype(/*something*/)>;
// HINT: l'operatore "," potrebbe aiutarvi!
template <typename T, typename Check = void>
struct hasFoo {
enum { value = false };
};
template <typename T>
struct hasFoo<T, decltype(std::declval<T>().foo(), void())> {
using type = decltype(std::declval<T>().foo());
enum { value = true };
};
// ...
struct A {};
struct B { int foo(); };
std::cout << hasFoo<A>::value << '\n';
std::cout << hasFoo<B>::value << '\n';
std::cout << std::is_same<int, hasFoo<B>::type>::value << '\n';
void foo(char c, int x) {
std::cout << c << ' ' << x << '\n';
}
int main()
{
// Prints 'c' 7
callFunction(foo, 0.2, 'c', "string", 99u, 7);
return 0;
}
template <typename... Args>
constexpr int tuple_size(std::tuple<Args...>) {
return sizeof...(Args);
}
// ...
// Prints 2
std::cout << tuple_size(std::tuple<int, double>()) << '\n';
template <typename... Args>
struct WrapInTuple {
using type = std::tuple<Args...>;
};
template </* ???? */>
struct getFunctionArguments;
template </* ???? */>
struct getFunctionArguments</* ???? */> {
using args = /* ???? */ ;
};
// ...
void foo(char, int);
static_assert(std::is_same<
std::tuple<char, int>,
getFunctionArguments<decltype(&foo)>::args
>::value, "No match!");
// Puntatore a funzione
ReturnType (*)(Arg1, Arg2, Arg3, ...)
// Variadic typename
typename... Args
// Pack expansion
Args...
// Parameter pack expansion available in:
// - Function argument lists (when calling)
// - Function parameter lists (when defining)
// - Template argument lists (when instantiating/partial specialization)
// - Template parameter lists (when defining)
// - Braced lists initializers
// - Lambda capture lists
// - Some others...
template <typename... Args>
std::tuple<Args...> simple_make_tuple(Args&&... args) {
// <-- pattern --> dots
return std::tuple<Args...>(std::forward<Args>(args) ... );
}
template </* ???? */>
void print(/* ???? */) {
// print all arguments separated by '\n';
}
template <int...> struct IdPack {};
template </* ???? */>
void print_tuple_elements(std::tuple</* ???? */>, IdPack</* ???? */> ids) {
// call print() with the tuple elements specified in ids
}
// ...
// Prints all
print("a", 1, "b", 0.5, 7, 'c', true);
// Prints 1, 0.5, 7
print_tuple_elements(std::make_tuple("a", 1, "b", 0.5, 7, 'c', true),
IdPack<1,3,4>());
// SINTASSI
pattern ...
template <int N>
struct Print {
void operator()() const {
std::cout << N << ' ';
Print<N-1>()();
}
};
template <>
struct Print<0> {
void operator()() const {
std::cout << 0 << '\n';
}
};
// ...
Print<5>()();
// 5 4 3 2 1 0
template <typename T>
struct TupleSize;
template <>
struct TupleSize<std::tuple<>> {
static constexpr auto size = 0;
};
template <typename T, typename... Args>
struct TupleSize<std::tuple<T, Args...>> {
static constexpr auto size = 1 +
TupleSize<std::tuple<Args...>>::size;
};
// ...
// Prints 2
std::cout << TupleSize<std::tuple<int, char>>::size << '\n';
template </* ???? */>
struct AreTupleTypesEqual;
template </* ???? */>
struct AreTupleTypesEqual</* ???? */> {
enum { value = /* ???? */ };
};
// ...
// Prints 0
std::cout << AreTupleTypesEqual<std::tuple<int, char>,
std::tuple<char>>::value << '\n';
// Prints 1
std::cout << AreTupleTypesEqual<std::tuple<int, char>,
std::tuple<int, char>>::value << '\n';
// SINTASSI
template <typename T>
struct TupleUnpack;
template <>
struct TupleUnpack<std::tuple<>>; // Final case
template <typename T, typename... Args>
struct TupleUnpack<std::tuple<T, Args...>>; // Unpacking
template <int M/* , ???? */>
struct TuplesAreEqualUpToImpl;
template <int M/* , ???? */>
struct TuplesAreEqualUpToImpl</* ???? */> {
static constexpr int N = /* ???? */;
};
template <typename T, typename U>
struct TuplesAreEqualUpTo {
static constexpr int N = TuplesAreEqualUpToImpl<0, T, U>::N;
};
// ...
static_assert(TuplesAreEqualUpTo<std::tuple<int, double>,
std::tuple<int, char>>::N == 1, "Error!");
// SINTASSI
template <typename T>
struct TupleUnpack;
template <>
struct TupleUnpack<std::tuple<>>; // Final case
template <typename T, typename... Args>
struct TupleUnpack<std::tuple<T, Args...>>; // Unpacking
template <int N, typename T, typename U, int... IDs>
struct Matcher;
template <int N, typename... B, int... IDs>
struct Matcher<N, std::tuple<>, std::tuple<B...>, IDs...> {
using type = IdPack<IDs...>;
};
template <int N, typename F, typename... A, typename... B, int... IDs>
struct Matcher<N, std::tuple<F, A...>, std::tuple<F, B...>, IDs...> {
using type = typename Matcher<N+1, std::tuple<A...>,
std::tuple<B...>, IDs..., N>::type;
};
template <int N, typename FA, typename... A,
typename FB, typename... B, int... IDs>
struct Matcher<N, std::tuple<FA, A...>, std::tuple<FB, B...>, IDs...> {
using type = typename Matcher<N+1, std::tuple<FA, A...>,
std::tuple<B...>, IDs...>::type;
};
template <typename F, typename... Args>
void callFunction(F f, Args&& ...args) {
using FArgs = typename getFunctionArguments<F>::args;
using IdList = typename Matcher<0, FArgs, std::tuple<Args...>>::type;
caller(f, std::make_tuple(args...), IdList());
}
void foo(char c, int x) {
std::cout << c << ' ' << x << '\n';
}
int main()
{
callFunction(foo, 0.2, 'c', "string", 99u, 7);
return 0;
}