#include <iostream>
using namespace std;
template <bool b, typename T, typename U>
class Select;
template <typename T, typename U>
class Select<true, T, U>
{
public:
using type = T;
};
template <typename T, typename U>
class Select<false, T, U>
{
public:
using type = U;
};
template <typename Type>
class EmptyList
{
public:
using type = Type;
};
template <typename Type, Type Value>
class ValueWrapper
{
public:
using type = Type;
static constexpr Type value = Value;
};
template <typename Left, typename Right>
class Pair
{
public:
using first = Left;
using rest = Right;
};
template <typename Type, Type First, Type ... Rest>
class Make_List
{
public:
using result = Pair<ValueWrapper<Type, First>,
typename Make_List<Type, Rest...>::result>;
};
template <typename Type, Type Last>
class Make_List<Type, Last>
{
public:
using result = Pair<ValueWrapper<Type, Last>, EmptyList<Type>>;
};
template <typename T, T val>
class DivBy5
{
public:
static constexpr bool value = val % 5 == 0;
};
template <typename List, template <typename T, T v> class Pred>
class Filter;
template <typename Type, template <typename T, T v> class Pred>
class Filter<EmptyList<Type>, Pred>
{
public:
using result = EmptyList<Type>;
};
template <typename First, typename Rest, template <typename T, T v> class Pred>
class Filter<Pair<First, Rest>, Pred>
{
public:
using result = typename Select<Pred<typename First::type, First::value>::value,
Pair<First, typename Filter<Rest, Pred>::result>,
typename Filter<Rest, Pred>::result>::type;
};
template <typename Type>
void PrintList(EmptyList<Type>)
{
}
template <typename First, typename Rest>
void PrintList(Pair<First, Rest>)
{
cout << First::value << endl;
PrintList(Rest());
}
int main()
{
using original = Make_List<int, 1, 2, 3, 10, 15, 20, 25, 123, 15>::result;
using filtered = Filter<original, DivBy5>::result;
PrintList(original());
cout << endl;
PrintList(filtered());
}
I2luY2x1ZGUgPGlvc3RyZWFtPgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKdGVtcGxhdGUgPGJvb2wgYiwgdHlwZW5hbWUgVCwgdHlwZW5hbWUgVT4KY2xhc3MgU2VsZWN0OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHR5cGVuYW1lIFU+CmNsYXNzIFNlbGVjdDx0cnVlLCBULCBVPgp7CnB1YmxpYzoKICAgIHVzaW5nIHR5cGUgPSBUOwp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHR5cGVuYW1lIFU+CmNsYXNzIFNlbGVjdDxmYWxzZSwgVCwgVT4KewpwdWJsaWM6CiAgICB1c2luZyB0eXBlID0gVTsKfTsKCgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVHlwZT4KY2xhc3MgRW1wdHlMaXN0CnsKcHVibGljOgogICAgdXNpbmcgdHlwZSA9IFR5cGU7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVHlwZSwgVHlwZSBWYWx1ZT4KY2xhc3MgVmFsdWVXcmFwcGVyCnsKcHVibGljOgogICAgdXNpbmcgdHlwZSA9IFR5cGU7CiAgICBzdGF0aWMgY29uc3RleHByIFR5cGUgdmFsdWUgPSBWYWx1ZTsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBMZWZ0LCB0eXBlbmFtZSBSaWdodD4KY2xhc3MgUGFpcgp7CnB1YmxpYzoKICAgIHVzaW5nIGZpcnN0ID0gTGVmdDsKICAgIHVzaW5nIHJlc3QgPSBSaWdodDsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUeXBlLCBUeXBlIEZpcnN0LCBUeXBlIC4uLiBSZXN0PgpjbGFzcyBNYWtlX0xpc3QKewpwdWJsaWM6CiAgICB1c2luZyByZXN1bHQgPSBQYWlyPFZhbHVlV3JhcHBlcjxUeXBlLCBGaXJzdD4sCiAgICAgICAgICB0eXBlbmFtZSBNYWtlX0xpc3Q8VHlwZSwgUmVzdC4uLj46OnJlc3VsdD47Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVHlwZSwgVHlwZSBMYXN0PgpjbGFzcyBNYWtlX0xpc3Q8VHlwZSwgTGFzdD4KewpwdWJsaWM6CiAgICB1c2luZyByZXN1bHQgPSBQYWlyPFZhbHVlV3JhcHBlcjxUeXBlLCBMYXN0PiwgRW1wdHlMaXN0PFR5cGU+PjsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCBUIHZhbD4KY2xhc3MgRGl2Qnk1CnsKcHVibGljOgogICAgc3RhdGljIGNvbnN0ZXhwciBib29sIHZhbHVlID0gdmFsICUgNSA9PSAwOwp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIExpc3QsIHRlbXBsYXRlIDx0eXBlbmFtZSBULCBUIHY+IGNsYXNzIFByZWQ+CmNsYXNzIEZpbHRlcjsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUeXBlLCB0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgVCB2PiBjbGFzcyBQcmVkPgpjbGFzcyBGaWx0ZXI8RW1wdHlMaXN0PFR5cGU+LCBQcmVkPgp7CnB1YmxpYzoKICAgIHVzaW5nIHJlc3VsdCA9IEVtcHR5TGlzdDxUeXBlPjsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBGaXJzdCwgdHlwZW5hbWUgUmVzdCwgdGVtcGxhdGUgPHR5cGVuYW1lIFQsIFQgdj4gY2xhc3MgUHJlZD4KY2xhc3MgRmlsdGVyPFBhaXI8Rmlyc3QsIFJlc3Q+LCBQcmVkPgp7CnB1YmxpYzoKICAgIHVzaW5nIHJlc3VsdCA9IHR5cGVuYW1lIFNlbGVjdDxQcmVkPHR5cGVuYW1lIEZpcnN0Ojp0eXBlLCBGaXJzdDo6dmFsdWU+Ojp2YWx1ZSwKICAgICAgICAgIFBhaXI8Rmlyc3QsIHR5cGVuYW1lIEZpbHRlcjxSZXN0LCBQcmVkPjo6cmVzdWx0PiwKICAgICAgICAgIHR5cGVuYW1lIEZpbHRlcjxSZXN0LCBQcmVkPjo6cmVzdWx0Pjo6dHlwZTsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUeXBlPgp2b2lkIFByaW50TGlzdChFbXB0eUxpc3Q8VHlwZT4pCnsKfQoKdGVtcGxhdGUgPHR5cGVuYW1lIEZpcnN0LCB0eXBlbmFtZSBSZXN0Pgp2b2lkIFByaW50TGlzdChQYWlyPEZpcnN0LCBSZXN0PikKewogICAgY291dCA8PCBGaXJzdDo6dmFsdWUgPDwgZW5kbDsKICAgIFByaW50TGlzdChSZXN0KCkpOwp9CgppbnQgbWFpbigpCnsKICAgIHVzaW5nIG9yaWdpbmFsID0gTWFrZV9MaXN0PGludCwgMSwgMiwgMywgMTAsIDE1LCAyMCwgMjUsIDEyMywgMTU+OjpyZXN1bHQ7CiAgICB1c2luZyBmaWx0ZXJlZCA9IEZpbHRlcjxvcmlnaW5hbCwgRGl2Qnk1Pjo6cmVzdWx0OwogICAgUHJpbnRMaXN0KG9yaWdpbmFsKCkpOwogICAgY291dCA8PCBlbmRsOwogICAgUHJpbnRMaXN0KGZpbHRlcmVkKCkpOwp9Cg==