//------------------------------+---------------------------------------------------------------

//  literal supplements

//  prefix "cstr" means literal string


template< uu size >

using   cstr_t                  = const char( & )[ size ];


template< uu size >

using   cstrarr_t               = const std::array< const char, size >;


//------------------------------+---------------------------------------------------------------


template< uu... ns >

using   seq                     = std::index_sequence< ns... >;

template< uu n >

using   make_seq                = std::make_index_sequence< n >;


template< class seq, uu from >  struct  index_from;

template< uu...  ns, uu from >  struct  index_from< seq< ns...>, from >

{

    using   type                = seq< from + ns... >;

};


template< uu from, uu to >      using   make_range =

    typename index_from< make_seq< to - from + 1 >, from >::type;


template< uu... ns >

rigid   oo                      make_array( seq< ns... > )

{

    return  std::array< uu, sizeof...( ns ) > { { ns... } };

}

//------------------------------+---------------------------------------------------------------


class                           CSTR

{

    template< uu size1, uu... ns1, uu size2, uu... ns2 >

    static  rigid   oo          cat( cstrarr_t< size1 > str1, cstrarr_t< size2 > str2,

                                     seq< ns1... >, seq< ns2... > )

    {

        return  cstrarr_t< sizeof...( ns1 ) + sizeof... ( ns2 ) >

                { str1[ ns1 ]... , str2[ ns2 ]... };

    }


    template< uu size, uu... ns >

    static  rigid   oo          make_array( cstr_t< size > str, seq< ns... > )

    {

        return  cstrarr_t< size >{ { str[ ns ]... } };

    }


public:

    //--------------------------+---------------------------------------------------------------


    template< uu size1, uu size2 >

    static  rigid   oo          cat( cstrarr_t< size1 > str1, cstrarr_t< size2 > str2 )

    {

        return  cat( str1, str2, make_seq< size1 - 1 >{}, make_seq< size2 >{} );

    }

    /// casters ----------------+---------------------------------------------------------------


    template< uu size1, uu size2 >

    static  rigid   oo          cat( cstr_t< size1 > str1, cstr_t< size2 > str2 )

    {

        return  cat( make_array( str1, make_seq< size1 >{} ),

                     make_array( str2, make_seq< size2 >{} ) );

    }


    template< uu size1, uu size2 >

    static  rigid   oo          cat( cstr_t< size1 > str1, cstrarr_t< size2 > str2 )

    {

        return  cat( make_array( str1, make_seq< size1 >{} ), str2 );

    }


    template< uu size1, uu size2 >

    static  rigid   oo          cat( cstrarr_t< size1 > str1, cstr_t< size2 > str2 )

    {

        return  cat( str1, make_array( str2, make_seq< size2 >{} ) );

    }

    //--------------------------+---------------------------------------------------------------


    template< uu size, uu sub_index, uu sub_size >

    static  rigid   oo          sub( cstrarr_t< size > str )

    {

        return  cat( str, make_array( "", make_seq< 1 >{} ),

                make_range< sub_index, sub_index + sub_size - 1 >{}, make_seq< 1 >{} );

    }

    /// caster -----------------+---------------------------------------------------------------


    template< uu size, uu sub_index, uu sub_size >

    static  rigid   oo          sub( cstr_t< size > str )

    {

        return  sub< size, sub_index, sub_size >( make_array( str, make_seq< size >{} ) );

    }

    //--------------------------+---------------------------------------------------------------

    //  length with null string terminator

    template< uu size1 >

    static  rigid   oo          size( cstr_t< size1 > str )

    {

        return  size1;

    }


    //  equal to strlen

    template< uu size1 >

    static  rigid   oo          length( cstr_t< size1 > str )

    {

        return  size1 - 1;

    }

};


#define cstrcat( s1, s2 )       CSTR::cat( s1, s2 ).data()

#define cstrsub( s, s_i, s_sz ) CSTR::sub< sizeof s, s_i, s_sz >( s ).data()

//------------------------------+---------------------------------------------------------------



리터럴 문자열을 리터럴 상태로 붙였다 나눴다 할 수 있음 ( strcat, substr )

VC++ 컴파일러가 바보라 한참 우회했네.