#include<iostream>
#include<cctype>
#include<utility>
#include<cstddef>

/*
 * 1. Define types, based in std::integral_constant and std::integer_sequence, to store our data
 * 2. map_types_over_integer_constants (to concat the individual char-integral_constants into one pack of chars
 * 3. constexpr_strlen
 * 4. the macro the defines the relevant lambda, and calls the above functions
 */

template<char c>
using Char = std::integral_constant<char,c>;

template<char... c>
struct CharPack : std::integer_sequence<char, c...> {
    static constexpr const char value0[] = {c...,'\0'};
    template< template<char...> class Template>
    using apply = Template<c...>; // This is in order to 'extract' the chars later
};
template<char... c>
constexpr const char CharPack<c...>:: value0[];

template<typename F, typename T>
struct map_types_over_integer_constants;
template<typename F, size_t... i>
struct map_types_over_integer_constants<F, std::integer_sequence<size_t, i...> > {
    using type = CharPack< F::get()[i] ... >;
};
constexpr size_t constexpr_strlen(const char * s) {
    return (*s=='\0')?0:(1+constexpr_strlen(s+1));
}

template<typename F>
struct map_to_each_char_in_string {
    using seq1N = std:: make_index_sequence< constexpr_strlen(F::get()) >;
    using type = typename map_types_over_integer_constants<F, seq1N> :: type;
};

#define COMPILE_LITERAL_STRING_TO_CHARPACK(t_name, str) \
    struct t_name ## required_nested_one {      \
        constexpr static const char * get() { return str; }      \
    };      \
    using t_name = map_to_each_char_in_string<t_name ## required_nested_one> :: type

/* The above lines could go in a header file, string_to_charpack.hpp or something */

using std:: cout;
using std:: endl;

template <char... c>
struct char_sequence_to_type;
template <> struct char_sequence_to_type< 'i','n','t' > { using type = int; };
template <> struct char_sequence_to_type< 'c','h','a','r' > { using type = char; };
template <> struct char_sequence_to_type< 's','t','r','i','n','g' > { using type = std:: string; };
template <char... c>
using char_sequence_to_type_t = typename char_sequence_to_type<c...>::type;

int main() {
    COMPILE_LITERAL_STRING_TO_CHARPACK(compiled_hello, "hello world");
    std:: cout << compiled_hello :: value0 << std:: endl;

    COMPILE_LITERAL_STRING_TO_CHARPACK(compiled_i, "int");
    COMPILE_LITERAL_STRING_TO_CHARPACK(compiled_c, "char");
    COMPILE_LITERAL_STRING_TO_CHARPACK(compiled_s, "string");
    static_assert(std::is_same< compiled_i::apply<char_sequence_to_type_t> ,int>::value, "int");
    static_assert(std::is_same< compiled_c::apply<char_sequence_to_type_t> ,char>::value, "char");
    static_assert(std::is_same< compiled_s::apply<char_sequence_to_type_t> ,std:: string>::value, "string");
}
