#include <iostream>
#include <array>
#include <string>

// Hilfsstrukturen zur Generierung einer Sequenz zwecks statischer Iteration

template<unsigned int...> struct Seq{ using type = Seq; };

template<class S1, class S2> struct ConcatI;

template<unsigned int... I1, unsigned int... I2>
struct ConcatI<Seq<I1...>, Seq<I2...>>
  : Seq<I1..., (sizeof...(I1)+I2)...>{};

template<class S1, class S2>
using Concat = typename ConcatI<S1, S2>::type;

template<size_t N> struct GenSeqI;
template<size_t N> using GenSeq = typename GenSeqI<N>::type;

template<size_t N>
struct GenSeqI : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};

template<> struct GenSeqI<0> : Seq<>{};
template<> struct GenSeqI<1> : Seq<0>{};
	
// Hilfsstrukturen zum Zuschneiden des Strings

template <size_t N, size_t C, typename X>
struct Helper;

template <size_t N, size_t C, size_t... I>
struct Helper<N, C, Seq<I...>> {
	constexpr static std::array<char, C+1> cut (const char (&str) [N]) {
		return {{ str [I]..., 0 }};
	}
};

/*
  Zuschneide-Funktion schneidet ein String (char-Array) und gibt ein std::array<char,C+1> mit der gewünschten Länge zurück
  inklusive Null-Byte. C gibt die gewünschte String-Länge an.
*/
template <size_t C, size_t N>
constexpr std::array<char, C+1> cutString (const char (&str) [N]) {
	return Helper<N, C, GenSeq<C>>::cut (str);
}

// Beispiel #1

// Schneide String.
constexpr auto x = cutString<3> (__VERSION__);
// x.data() ist jetzt ein const char* von der Länge x.size() = 3.

int main () {
	// Gebe String von Beispiel #1 aus.
	std::cout << x.data () << '\n';
	
	
	// Beispiel #2
	constexpr auto y = cutString<5> ("Hello, world!");
	std::cout << y.data () << '\n';
	
	return 0;
}