#include <iostream>
#include <set>
#include <stdexcept>
#include <string>
#include <functional>

template<typename T>
struct identity
{
    using type = T;
};

template<char ... Ch>
struct const_string : identity<const_string<Ch...>>
{
	static char constexpr nt_arr[]{ Ch..., '\0' };

	static std::size_t constexpr length = sizeof...(Ch);

private:
	constexpr std::size_t _count_impl( char c, std::size_t index )
	{
		return nt_arr[index] == c + (index == 0 ? 0 : _count_impl(c, index - 1));
	}

public:
	constexpr std::size_t count( char c )
	{ return _count_impl( c, sizeof(nt_arr) - 1 );  }
};

template<char ... Ch>
char constexpr const_string<Ch...>::nt_arr[];

/// concat_strings //////////////////////////////////////////////////////////////////

template<typename, typename> struct concat_strings;

template<char ... first,
         char ... second>
struct concat_strings<const_string<first...>, const_string<second...>> : const_string<first..., second...> {};

/// type_list ///////////////////////////////////////////////////////////////////////

// Geht natürlich auch ohne Rekursion, ist nunmal auf die Schnelle gemacht:
template<std::size_t index, typename T, typename ... Types>
struct at : at<index-1, Types...> {};
template<typename T, typename ... Types>
struct at<0, T, Types...> : identity<T> {};

template<typename ... Types>
struct type_list : identity<type_list<Types...>>
{
	static std::size_t constexpr length = sizeof...(Types);

	template<std::size_t index>
	struct get : at<index, Types...> {};
};

template<typename... Args>
type_list<Args...> arg_type_list( Args&&... );

template<std::size_t i, typename T>
struct indexed_type
{
	static constexpr std::size_t index = i;
	using type = T;
};

/// concat_type_lists //////////////////////////////////////////////////////////

template<typename, typename> struct concat_type_lists;

template<typename ... first,
         typename ... second>
struct concat_type_lists<type_list<first...>, type_list<second...>> : type_list<first..., second...> {};

/// split ////////////////////////////////////////////////////////////////////////

template<char, typename, typename, typename> struct split_on;

template<char token,
         typename ... pairs>
struct split_on< token, type_list<pairs...>, const_string<>, const_string<> > : type_list<pairs...> {};


template<char token,
         char ... last,
         typename ... pairs>
struct split_on< token, type_list<pairs...>, const_string<last...>, const_string<> > : type_list< pairs..., indexed_type<0, const_string<last...>> > {};

// Kein Token vorhanden:
template<char token,
         char current,
         char ... last,
         char ... tail,
         typename ... pairs>
struct split_on< token, type_list<pairs...>, const_string<last...>, const_string<current, tail...> > : split_on<token, type_list<pairs...>, const_string<last..., current>, const_string<tail...>> {};

template<char C>
struct enable_if_digit
{
	static_assert( C >= '0' && C <= '9', "Not a digit!" );

	static constexpr char ch = C;
	static constexpr int number = C - '0';
};

template<char token,
         char digit,
         char ... last,
         typename ... pairs>
struct split_on< token, type_list<pairs...>, const_string<last...>, const_string<token, digit> > :
	type_list<pairs..., indexed_type<enable_if_digit<digit>::number, const_string<last...>>, indexed_type<0, const_string<>>> {};

template<char token,
         char digit,
         char ... last,
         char ... tail,
         typename ... pairs>
struct split_on< token, type_list<pairs...>, const_string<last...>, const_string<token, digit, tail...> > :
	split_on<token, type_list< pairs..., indexed_type<enable_if_digit<digit>::number, const_string<last...>> >, const_string<>, const_string<tail...>> {};

template<char token,
         char ... last,
         char ... tail,
         typename ... pairs>
struct split_on< token, type_list<pairs...>, const_string<last...>, const_string<token, token, tail...> > : split_on<token, type_list<pairs...>, const_string<last..., token, token>, const_string<tail...>> {};

template<char c, typename> struct split;
template<char c, char... chars> struct  split<c, const_string<chars...>> : split_on<c, type_list<>, const_string<>, const_string<chars...>> {};

/// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template<char, typename> struct rtrim;
template<char token, char first, char ... ch>
struct rtrim<token, const_string<first, ch...>> : concat_strings<const_string<first>, typename rtrim<token, const_string<ch...>>::type> {};
template<char token, char ... ch>
struct rtrim<token, const_string<token, ch...>> : const_string<> {};
template<char token>
struct rtrim<token, const_string<>> : const_string<> {};

/// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template<std::size_t Index, typename T>
struct rack
{
	static constexpr std::size_t index = Index;

	T&& arg;

	rack( T&& a ):
		arg( std::forward<T>(a) ) {}
};

/// index-list (v. camper)

template<int ... args>
struct index_list
{
    static constexpr int arr[]{args...};
    using type = index_list;
};

template <typename T, typename U> struct concat_list;
template <int... i, int... j>
struct concat_list<index_list<i...>,index_list<j...>>
: index_list<i..., (sizeof...(i)+i)..., (2*sizeof...(i)+j)...> {};

template <int N> struct make_index_list
: concat_list<typename make_index_list<N/2>::type, typename make_index_list<N%2>::type> {};
template <> struct make_index_list<1> : index_list<0> {};
template <> struct make_index_list<0> : index_list<> {};

/// </camper> /

template<typename, typename...> struct Indicer;

template<int... indices, typename... Args>
struct Indicer<index_list<indices...>, Args...> : rack<indices, Args>...
{
	Indicer( Args&&... args ):
		rack<indices, Args>(std::forward<Args>(args))... {}
};

template<typename format_string,
         typename CharT,
	     typename Traits,
	     typename index_list>
struct ts_printf_env;

template<typename format_string,
         typename CharT,
	     typename Traits,
	     int... indices>
struct ts_printf_env<format_string, CharT, Traits, index_list<indices...>>
{
	static char constexpr format_sign = '%';

	using string_list = typename split<format_sign, format_string>::type;

private:

	template<std::size_t type_list_index>
	static void ts_printf_impl( std::basic_ostream<CharT, Traits>& os )
	{
		using to_put = typename string_list::template get<type_list_index>::type::type;

		if( os.rdbuf()->sputn( to_put::nt_arr, to_put::length ) != to_put::length )
			os.setstate( std::ios_base::badbit );
	}

	template<std::size_t type_list_index,
			 typename FirstArg,
			 typename ...Args>
	static void ts_printf_impl( std::basic_ostream<CharT, Traits>& os,
								FirstArg&& first,
								Args&&... tail)
	{
		ts_printf_impl<type_list_index>( os );

		if( os << std::forward<FirstArg>(first) )
			ts_printf_impl<type_list_index + 1>( os, std::forward<Args>(tail)... );
	}

public:

	template<typename ... Args>
	static std::basic_ostream<CharT, Traits>& ts_printf( std::basic_ostream<CharT, Traits>& os, Args&&... args )
	{
		static_assert( sizeof...(Args) + 1 == string_list::length, "Invalid format string!" );

		typename std::basic_ostream<CharT, Traits>::sentry ok{os};

		if( ok ) try
		{
			Indicer<typename make_index_list<sizeof...(Args)>::type, Args...> indicer( std::forward<Args>(args)... );

			#define index string_list::template get<indices>::type::index
			ts_printf_impl<0>( os, indicer.rack< index,
												 typename at<index, Args...>::type >::arg... );
			#undef index
		}
		catch( std::ios::failure const& )
		{ throw; }
		catch(...)
		{
			os.clear( os.rdstate() | std::ios_base::badbit );
			if( os.exceptions() & std::ios_base::badbit )
				throw;
		}

		return os;
	}
};

#define SPLIT_1(str,pos)  str [ pos < sizeof str ? pos : sizeof(str) - 1 ]
#define SPLIT_2(str,x)  SPLIT_1(str,x), SPLIT_1(str,x + 1)
#define SPLIT_4(str,x)  SPLIT_2(str,x), SPLIT_2(str,x + 2)
#define SPLIT_8(str,x)  SPLIT_4(str,x), SPLIT_4(str,x + 4)
#define SPLIT_16(str,x) SPLIT_8(str,x), SPLIT_8(str,x + 8)
#define SPLIT_32(str,x) SPLIT_16(str,x), SPLIT_16(str,x + 16)
#define SPLIT_64(str,x) SPLIT_32(str,x), SPLIT_32(str,x + 32)
#define SPLIT_128(str,x) SPLIT_64(str,x), SPLIT_64(str,x + 64)

#define ts_printf(os, format, ...) ts_printf_env<typename rtrim<'\0', const_string<SPLIT_128(format, 0)>>::type, \
                                                 decltype(os)::char_type, \
                                                 decltype(os)::traits_type, \
                                                 make_index_list<decltype(arg_type_list(__VA_ARGS__))::length>::type>::ts_printf( os, __VA_ARGS__ )


int main()
{
	ts_printf(std::cout, "%1 + %2 = %0", 10, 6, 4);
}
