Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
template<typename T, typename ...Args>
struct Exists :
std::false_type
{
};
template<typename T, typename ...Args>
struct Exists<T, T, Args...> :
std::true_type
{
};
template<typename T, typename NotT, typename ...Args>
struct Exists<T, NotT, Args...> :
std::integral_constant<bool, Exists<T, Args...>::value>
{
};
Вопрос 1:Например, так:
А как по этому TypeList'у foreach'eм пройтись так чтоб без for'a? :)
Скажем в ваш TypeList ложим список классов со статическими функциями. А потом вызываем некую статическую do_func() из них.
template <class First, class Rest>
struct typelist;
struct nil;
// ----------------------------------------------------------------------------
template <class TypeCollection, template <class T> class StaticFunctor>
struct ForEach;
template <class Last, template <class T> class StaticFunctor>
struct ForEach<typelist<Last, nil>, StaticFunctor>
{
static void iterate()
{
StaticFunctor<Last>::call();
}
};
template <class First, class Rest, template <class T> class StaticFunctor>
struct ForEach<typelist<First, Rest>, StaticFunctor>
{
static void iterate()
{
StaticFunctor<First>::call();
ForEach<Rest, StaticFunctor>::iterate();
}
};
#define FOR_EACH(collection, action) \
ForEach<collection, action>::iterate()
#define DEFINE_STATIC_CALLER_FUNCTOR(function) \
namespace Call \
{ \
template <class T> \
struct function \
{ \
static void call() \
{ \
T::function(); \
} \
}; \
}
// ----------------------------------------------------------------------------
#include <iostream>
#define DEFINE_CLASS_SPECIMEN(name) \
struct name \
{ \
static \
void do_function() \
{ \
std::cout << #name "::function()\n"; \
} \
};
DEFINE_CLASS_SPECIMEN(A)
DEFINE_CLASS_SPECIMEN(B)
DEFINE_CLASS_SPECIMEN(C)
typedef typelist<A, typelist<B, typelist<C, nil> > > TestTypelist;
DEFINE_STATIC_CALLER_FUNCTOR(do_function)
int main()
{
FOR_EACH(TestTypelist, Call::do_function);
}
Вопрос 2:
...
#define DEFINE_METHOD_CHECKER(RETURN_TYPE, METHOD_NAME, PARAMETERS) \
template<typename T> \
struct Is ## METHOD_NAME ## MemberFunctionExists \
{ \
private: \
typedef char True; \
typedef char (&False)[2]; \
template<typename U, RETURN_TYPE (U::*)PARAMETERS = &U::METHOD_NAME>\
struct Checker \
{ \
typedef True Type; \
}; \
template<typename U> \
static typename Checker<U>::Type Tester(const U*); \
static False Tester(...); \
public: \
enum { value = (sizeof(Tester(static_cast<const T*>(0))) == sizeof(True)) }; \
}
// IsMethodMemberFunctionExists<T>::value
DEFINE_METHOD_CHECKER(int, Method, (bool));
// IsTestMemberFunctionExists<T>::value
DEFINE_METHOD_CHECKER(int*, Test, (int&, char));
#include <iostream>
class Exists
{
public:
int Method(bool);
int* Test(int&, char);
};
class NotExists
{
};
int main()
{
std::cout << IsMethodMemberFunctionExists<Exists>::value << std::endl;
std::cout << IsTestMemberFunctionExists<Exists>::value << std::endl;
std::cout << IsMethodMemberFunctionExists<NotExists>::value << std::endl;
std::cout << IsTestMemberFunctionExists<NotExists>::value << std::endl;
}
DEFINE_METHOD_CHECKER(int, Method, (bool) const);
DEFINE_METHOD_CHECKER(int*, Test, (int&, char) volatile);
#define DEFINE_TEMPLATE_METHOD_CHECKER(RETURN_TYPE, METHOD_NAME, PARAMETERS_INST, ARGS) \
template<typename T> \
struct Is ## METHOD_NAME ## TemplateMemberFunctionExists \
{ \
private: \
typedef char True; \
typedef char (&False)[2]; \
template<typename U, RETURN_TYPE (U::*)PARAMETERS_INST = &U::template METHOD_NAME ARGS >\
struct Checker \
{ \
typedef True Type; \
}; \
template<typename U> \
static typename Checker<U>::Type Tester(const U*); \
static False Tester(...); \
public: \
enum { value = (sizeof(Tester(static_cast<const T*>(0))) == sizeof(True)) }; \
}
// IsVCFailTemplateMemberFunctionExists<T>::value
DEFINE_TEMPLATE_METHOD_CHECKER(void, VCFail, (), <int>);
// IsVCOkTemplateMemberFunctionExists<T>::value
DEFINE_TEMPLATE_METHOD_CHECKER(void, VCOk, (int, bool), <int>);
#include <iostream>
class Exists
{
public:
template<typename T>
void VCFail();
template<typename T>
void VCOk(T, bool);
};
class NotExists
{
};
int main()
{
std::cout << IsVCOkTemplateMemberFunctionExists<Exists>::value << std::endl;
std::cout << IsVCOkTemplateMemberFunctionExists<NotExists>::value << std::endl;
//std::cout << IsVCFailTemplateMemberFunctionExists<Exists>::value << std::endl;
std::cout << IsVCFailTemplateMemberFunctionExists<NotExists>::value << std::endl;
}
// Делается по "накатанной" схеме - определяем основу шаблона.
// В этом случае шаблон инстанцируется для
// - любого другого шаблонного класса, который имеет один параметр(<b>Caller</b>)
// - любого другого типа(<b>TL</b>)
template<template<typename> class Caller, typename TL>
struct ForEach
{
};
// Дальше - уточняем - на самом деле мы хотим иметь только:
// - любой другой шаблонный класса, как первый аргумент(<b>Caller</b>)
// - именно какую-то версию <b>TypeList</b>, как другой аргумент
template<template<typename> class Caller, typename ...Args>
struct ForEach<Caller, TypeList<Args...>>
{
typedef TypeList<Args...> TL;
void operator()() const
{
// Для Caller<T> - должен быть перегружен operator(),
// где T - это TL::Head. Можно выбрать и любую другую ф-ю.
Caller<typename TL::Head>()();
// Рекурсия - вызываем всё то же для хвоста
ForEach<Caller, typename TL::Tail>()();
}
};
// Говорим, что когда список типов пуст - ничего не делать
template<template<typename> class Caller>
struct ForEach<Caller, EmptyTypeList>
{
void operator()() const
{
}
};
T:// Для любого типа
template<typename T>
struct Call
{
void operator()() const
{
std::cout << typeid(T).name() << std::endl;
}
};
// Делаем полную специализацию шаблона для 'float', допустим
template<>
struct Call<float>
{
void operator()() const
{
std::cout << "Call<float>" << std::endl;
}
};
typedef TypeList<double, float, float, double, int, char, char, int, char> TL;
ForEach<Call, TL>()();
double
Call<float>
Call<float>
double
int
char
char
int
char
TypeList и Крестики-нолики