#include <iostream>
#define reflect_base(t) \
typedef t base_type; \
typedef t type;
#define reflect(t) \
typedef typename t::type base_type; \
typedef t type;
template <typename R, typename P, typename = typename R::base_type>
struct inherit_base_pattern : public P { };
template <typename R, typename P>
struct inherit_base_pattern<R, P, R> { };
template <int I1, int I2>
struct adder { reflect_base(adder) };
template <int I1, int I2>
struct adder1 : public adder<I1, I2> { reflect(adder1) };
template <int I1, int I2>
struct adder2 : public adder<I1, I2> { reflect(adder2) };
template <typename A, int I>
struct fusedmultiplyadder
: public inherit_base_pattern< A, fusedmultiplyadder<typename A::base_type, I> >
{ reflect_base(fusedmultiplyadder) };
template <int i1, int i2, int i3>
void foo(fusedmultiplyadder<adder<i1, i2>, i3>)
{
std::cout << "fma: " << i1 << ", " << i2 << ", " << i3 << std::endl;
}
int main()
{
fusedmultiplyadder<adder1<2, 3>, 4> fma1;
foo(fma1);
fusedmultiplyadder<adder2<2, 3>, 4> fma2;
foo(fma2);
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgoKI2RlZmluZSByZWZsZWN0X2Jhc2UodCkgXAogICB0eXBlZGVmIHQgYmFzZV90eXBlOyBcCiAgIHR5cGVkZWYgdCB0eXBlOwoKI2RlZmluZSByZWZsZWN0KHQpIFwKICAgdHlwZWRlZiB0eXBlbmFtZSB0Ojp0eXBlIGJhc2VfdHlwZTsgXAogICB0eXBlZGVmIHQgdHlwZTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBSLCB0eXBlbmFtZSBQLCB0eXBlbmFtZSA9IHR5cGVuYW1lIFI6OmJhc2VfdHlwZT4Kc3RydWN0IGluaGVyaXRfYmFzZV9wYXR0ZXJuIDogcHVibGljIFAgeyB9Owp0ZW1wbGF0ZSA8dHlwZW5hbWUgUiwgdHlwZW5hbWUgUD4Kc3RydWN0IGluaGVyaXRfYmFzZV9wYXR0ZXJuPFIsIFAsIFI+IHsgfTsKICAgCnRlbXBsYXRlIDxpbnQgSTEsIGludCBJMj4Kc3RydWN0IGFkZGVyIHsgcmVmbGVjdF9iYXNlKGFkZGVyKSB9OwoKdGVtcGxhdGUgPGludCBJMSwgaW50IEkyPgpzdHJ1Y3QgYWRkZXIxIDogcHVibGljIGFkZGVyPEkxLCBJMj4geyByZWZsZWN0KGFkZGVyMSkgfTsKIAp0ZW1wbGF0ZSA8aW50IEkxLCBpbnQgSTI+CnN0cnVjdCBhZGRlcjIgOiBwdWJsaWMgYWRkZXI8STEsIEkyPiB7IHJlZmxlY3QoYWRkZXIyKSB9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIEEsIGludCBJPgpzdHJ1Y3QgZnVzZWRtdWx0aXBseWFkZGVyCiAgIDogcHVibGljIGluaGVyaXRfYmFzZV9wYXR0ZXJuPCBBLCBmdXNlZG11bHRpcGx5YWRkZXI8dHlwZW5hbWUgQTo6YmFzZV90eXBlLCBJPiA+CnsgcmVmbGVjdF9iYXNlKGZ1c2VkbXVsdGlwbHlhZGRlcikgfTsKCnRlbXBsYXRlIDxpbnQgaTEsIGludCBpMiwgaW50IGkzPgp2b2lkIGZvbyhmdXNlZG11bHRpcGx5YWRkZXI8YWRkZXI8aTEsIGkyPiwgaTM+KQp7CiAgIHN0ZDo6Y291dCA8PCAiZm1hOiAiIDw8IGkxIDw8ICIsICIgPDwgaTIgPDwgIiwgIiA8PCBpMyA8PCBzdGQ6OmVuZGw7Cn0KIAppbnQgbWFpbigpCnsKICAgZnVzZWRtdWx0aXBseWFkZGVyPGFkZGVyMTwyLCAzPiwgND4gZm1hMTsKICAgZm9vKGZtYTEpOwogICBmdXNlZG11bHRpcGx5YWRkZXI8YWRkZXIyPDIsIDM+LCA0PiBmbWEyOwogICBmb28oZm1hMik7CiAgIHJldHVybiAwOwp9