#include <iostream>

// define
#define ArggregateCategory(uniqename)	Category<__LINE__>

namespace arggregate
{

namespace detail
{

typedef class EOT
{
} EndOfTemplate, EndOfType;
	
/**
 * @brief	Aggregate Base
*/
class AggregateBase
{
protected:
	AggregateBase(void) : m_empty(true) {}
	void activate(void) { m_empty = false; }
public:
	bool empty(void) const { return m_empty; }
private:
	bool m_empty;
};

template<typename T>
class ValueType
{
	typedef T						value_type;
	typedef ValueType<value_type>	_Myt;
public:
	ValueType(void) {}
	ValueType(const value_type& rhs) : m_value(rhs) {}
	ValueType(const _Myt& rhs) : m_value(rhs.m_value) {}
	
	operator value_type& (void) { return m_value; }
	operator value_type (void) const { return m_value; }
	
	_Myt&	operator = (const value_type& rhs) { m_value = rhs; return *this; }
	_Myt&	operator = (const _Myt& rhs) { m_value = rhs.m_value; return *this; }
	
private:
	T m_value;
};

/**
 * @brief	デフォルト引数判別用の型
*/
template<typename T>
class DefaultArgument : public ValueType<T> 
{
public:
	DefaultArgument(void) {}
	DefaultArgument(const T& rhs) : ValueType<T>(rhs) {}
};

}

/**
 * @brief	カテゴリー
*/
template<int LINE>
class Category
{
	template<typename Aggregate>
	class Instance
	{
		static Aggregate	m_aggregate;
	public:
		static Aggregate&	GetInstance(void)	{ return m_aggregate; }
	};
	
	template<typename T, typename Aggregate>
	class AggregateList
	{
	public:
		static void add(const T& rhs)
		{
			Instance<typename Aggregate::InstantiateType>::GetInstance().add(rhs);
			AggregateList<T, typename Aggregate::NextType>::add(rhs);
		}
	};
	template<typename T>
	class AggregateList<T, detail::EOT>
	{
	public:
		static void add(const T&) {}
	};
	
public:
	/**
	 * @brief	型定義
	*/
	template<typename T, typename Aggregate>
	class Decl : public detail::ValueType<T>
	{
		typedef Decl<T, Aggregate>	_Myt;
	public:
		typedef _Myt	Type;
	public:
		Decl(const T& rhs) : detail::ValueType<T>(rhs), m_default(false)
		{
			AggregateList<T, Aggregate>::add(rhs);
		}
		Decl(const detail::DefaultArgument<T>& rhs) : detail::ValueType<T>(rhs), m_default(true)
		{
			// デフォルト引数の場合は集計しない
		}
		
	public:
		bool	is_default(void) const { return m_default; }
	private:
		bool	m_default;
	};
	
	/**
	 * @brief	デフォルト値の取得クラス
	*/
	template<typename T, typename SimpleAggregate>
	static detail::DefaultArgument<T> Value(const T& defalut_value)
	{
		return Instance<SimpleAggregate>::GetInstance().empty() ?
			defalut_value : static_cast<T>(Instance<SimpleAggregate>::GetInstance().value());
	}
};

template<int LINE>
template<typename Aggregate>
Aggregate	Category<LINE>::Instance<Aggregate>::m_aggregate;

/**
 * @brief	最小値
*/
template<typename T, typename Next=detail::EOT>
class Min : public detail::AggregateBase
{
	T m_value;
public:
	typedef Next	NextType;
	typedef Min<T, detail::EOT>	InstantiateType;

public:
	void	add(const T& value)
	{
		if( empty() || value < m_value )
		{
			m_value = value;
			activate();
		}
	}
	T		value(void) const { return m_value; }
};

/**
 * @brief	最大値
*/
template<typename T, typename Next=detail::EOT>
class Max : public detail::AggregateBase
{
	T m_value;
public:
	typedef Next	NextType;
	typedef Max<T, detail::EOT>	InstantiateType;

public:
	void	add(const T& value)
	{
		if( empty() || value > m_value )
		{
			m_value = value;
			activate();
		}
	}
	T		value(void) const { return m_value; }
};

}

// 集計カテゴリの定義（現状は行ごとにカテゴリ化される。）
typedef ::arggregate::ArggregateCategory(test)	Arggregate1;
typedef ::arggregate::ArggregateCategory(test)	Arggregate2;

typedef ::arggregate::Min<int, ::arggregate::Max<int> > MinMax;

void f1(Arggregate1::Decl< int, ::arggregate::Min<int> >::Type x=Arggregate1::Value< int, ::arggregate::Min<int> >(1000) )
{
	if( x.is_default() ) ::std::cout << x << ::std::endl;
}

void f2(Arggregate2::Decl< int, MinMax >::Type x1=Arggregate2::Value< int, ::arggregate::Min<int> >(-1)
	, Arggregate2::Decl< int, MinMax >::Type x2=Arggregate2::Value< int, ::arggregate::Max<int> >(1000) )
{
	::std::cout << x1 << ":" << x2 << ::std::endl;
}

int main(void)
{
	{
		::std::cout << "----- f1 ----- " << ::std::endl;

		f1();	// 集計情報 0 のため 通常デフォルト引数が渡される
		for( int i=10; i > 0; --i )
		{
			f1(i);	// 通常使用
		}
		f1();	// 集計した結果の最小値がデフォルト引数となる
	}
	
	{
		::std::cout << "----- f2 ----- " << ::std::endl;
		
		f2();	// 集計情報 0 のため 通常デフォルト引数が渡される
		for( int i=10; i > 0; --i )
		{
			f2(i);	// 第一引数のみ指定、第二引数にも集計結果が反映される
		}
		f2();	// 集計した結果の最小値がデフォルト引数となる
	}

	return 0;
}


