#include <iostream>
#include <inttypes.h>
#include <type_traits>

template <int F>
struct fp
{
	enum { BITS = F };
	int32_t s;
	
	template<class B = int, typename std::enable_if<!std::is_same<B, int32_t>::value>::type...>
	fp(const int & b) : s(((int32_t)b) << F) { }
	fp(const int32_t & b) : s(b << F) { }
	fp(const float & b) : s(b * (1 << F)) { }
	template<int T>
	fp(const fp<T> & b) { *this = b; }
	
	template<class B = int, typename std::enable_if<!std::is_same<B, int32_t>::value>::type...>
	fp & operator=(const int & b) { s = ((int32_t)b) << F; return *this; }
	fp & operator=(const int32_t & b) { s = b << F; return *this; }
	fp & operator=(const float & b) { s = b * (1 << F); return *this; }
	fp & operator=(const fp & b) { s = b.s; return *this; }
	
	template<int T>
	fp & operator=(const fp<T> & b)
	{
		if (T > F) { s = b.s >> (T - F); }
		else if (T < F) { s = b.s << (F - T); }
		else { s = b.s; }
		return *this;
	}

	/*fp & operator=(const int32_t & b)
	{
		s = b << F;
		return *this;
	}

	fp & operator=(const float & b)
	{
		s = b * (1 << F);
		return *this;
	}*/
	
	friend std::ostream & operator<<(std::ostream & os, const fp<F> & a) { os << a.s; return os; }
};

using fp824 = fp<24>;
using fp1616 = fp<16>;
using fp248 = fp<8>;

int main() {
	// your code goes here
	fp1616 a0(0); // error: ambiguous?!
	fp1616 a1(1); // error: ambiguous?!
	fp1616 a2(2); // error: ambiguous?!
	fp1616 a3(-2.5f);
	std::cout << a0 << std::endl;
	std::cout << a1 << std::endl;
	std::cout << a2 << std::endl;
	std::cout << a3 << std::endl;
	a0 = 5; // error: ambiguous?!
	a0 = 0; // error: ambiguous?!
	a0 = 3.4f;
	fp824 b1(1.2f);
	fp1616 b2(b1);
	fp248 b3(b2);
	b1 = b3;
	b1 = b2;
	return 0;
}