2014-01-07 3 views
2

У меня есть вектор mpl :: string. mpl :: ограничение размера строки - 32 элемента. Есть способ создать константный символ * массив во время компиляцииКак конкатенировать const char * во время компиляции

MACRO(z,i,data) data 
............. 
const char* array[] = { BOOST_PP_ENUM(SIZE,MACRO,mpl_vector) }; 

Но мне нужно получить один константный символ * строку во время компиляции. Как это сделать?

UPDATE Я создаю массив mpl :: string во время компиляции. Они сжаты (размер каждой строки около 25-31 с пределом 32). Я могу получить массив из него натягивает как

//first,second string etc is mpl::c_str<mpl_string>::value 
    const char* array_mpl_strings[] = {first_string,second_string .....}; 

Но мне нужна полная строка (не массив):

const char* string = first_stringsecond_string....; 

Как сделать «строка» из «array_mpl_strings»?

+1

http://cpp-next.com/archive/2012/10/using-strings-in-c-template-metaprograms/ –

+1

nop. Лимит - 32 символа. Максимальный размер mpl :: string. Я делаю его строковым, и он должен конкатенироваться. – crastinus

+0

Возможный дубликат http://stackoverflow.com/questions/4077369/concatenate-boostmplstring – Jarod42

ответ

1

Я не знаю причину о BOOST_MPL_STRING_MAX_LENGTH

но после может помочь, если вы можете преобразовать тип:

#include <cassert> 
#include <cstring> 
#include <tuple> 


template<char...Cs> struct seq 
{ 
    typedef const char (&arr_type)[sizeof...(Cs) + 1]; 
    static constexpr arr_type c_str() { return str; } 
    static constexpr char str[sizeof...(Cs) + 1] = {Cs..., '\0'}; 
}; 

template<char...Cs> 
constexpr char seq<Cs...>::str[sizeof...(Cs) + 1]; 


template<typename T, typename ... Ts> 
struct concat_seq; 

template<char...Cs> 
struct concat_seq<seq<Cs...>> : seq<Cs...> {}; 

template<char...Cs1, char...Cs2> 
struct concat_seq<seq<Cs1...>, seq<Cs2...>> : seq<Cs1..., Cs2...> {}; 

template<char...Cs1, char...Cs2, typename ... Ts> 
struct concat_seq<seq<Cs1...>, seq<Cs2...>, Ts...> : 
    concat_seq<seq<Cs1..., Cs2...>, Ts...> {}; 

template<typename ... Ts> 
struct concat_seq<std::tuple<Ts...>> : concat_seq<Ts...> {}; 

int main() 
{ 
    const char* s = concat_seq<std::tuple<seq<'h', 'e'>, seq<'l', 'l', 'o'>>>::c_str(); 

    assert(strcmp(s, "hello") == 0); 

    return 0; 
} 
+0

хороший вариант. Я думаю об этом. – crastinus

+0

Я думаю, что это может быть улучшено, чтобы иметь только последний 'static char [..]', чтобы уменьшить использование памяти ... – Jarod42

1

Для их интересовавший окончательный вариант:

#include <boost/preprocessor.hpp> 
#include <boost/static_assert.hpp> 
#include <boost/mpl/equal_to.hpp> 
#include <boost/mpl/if.hpp> 

#include <iostream> 
#include <cstring> 
#include <exception> 
#include <stdexcept> 


#define NUM_CHARS 32 
#define CHARS_GEN(count,i,data) data ## i 
#define GEN_CHARSP(N) BOOST_PP_ENUM(N,CHARS_GEN,char C) 
#define GEN_CHARS(N) BOOST_PP_ENUM(N,CHARS_GEN, C) 

/*Jarod42 classes*/ 
template<char...Cs> struct seq 
{ 
    typedef const char (&arr_type)[sizeof...(Cs) + 1]; 
    static constexpr arr_type c_str() { return str; } 
    static constexpr char str[sizeof...(Cs) + 1] = {Cs..., '\0'}; 
}; 

template<char...Cs> 
constexpr char seq<Cs...>::str[sizeof...(Cs) + 1]; 


template<typename T, typename ... Ts> 
struct concat_seq; 

template<char...Cs> 
struct concat_seq<seq<Cs...>> : seq<Cs...> { 
    typedef seq<Cs...> type; 
}; 

template<char...Cs1, char...Cs2> 
struct concat_seq<seq<Cs1...>, seq<Cs2...>> : seq<Cs1..., Cs2...> { 
    typedef seq<Cs1...,Cs2...> type; 
}; 

template<char...Cs1, char...Cs2, typename ... Ts> 
struct concat_seq<seq<Cs1...>, seq<Cs2...>, Ts...> : 
    concat_seq<seq<Cs1..., Cs2...>, Ts...> {}; 

template<typename ... Ts> 
struct concat_seq<std::tuple<Ts...>> : concat_seq<Ts...> {}; 

/*Abrahams function*/ 
template <int N> 
constexpr char at(char const(&s)[N], int i) 
{ 
    return i >= N ? '\0' : s[i]; 
} 

#define AT(count,i,s) at(s,i) 

namespace mpl = boost::mpl; 

/*My modification, but abraham's way */ 
template<size_t N> 
constexpr size_t str_size(const char (&a)[N]){ 
    return N-1; 
} 
#define PRE_MACRO(z,i,s) \ 
    typename               \ 
     mpl::if_<              \ 
     typename mpl::equal_to<mpl::int_<i>,mpl::int_<N> >::type,  \ 
       seq<GEN_CHARS(i)>, 
#define POST_MACRO(z,i,s) >::type 

/*TODO: incorect count of paramenters N is 31, params is 32*/ 
template <size_t N, GEN_CHARSP(NUM_CHARS)> 
struct create_sequence { 
    typedef 
    BOOST_PP_REPEAT(NUM_CHARS,PRE_MACRO,"") 
    void 
    BOOST_PP_REPEAT(NUM_CHARS,POST_MACRO,"") 
    type; 
}; 

#define _S(s) create_sequence<str_size(s),BOOST_PP_ENUM(NUM_CHARS,AT,s)>::type 

int main() 
{ 
     typedef _S("first_string_sequence ") sq1; 
     typedef _S("second_string_sequence ") sq2; 
     typedef _S("И такие строки ") sq3; 

     std::cout << sq1::c_str() << std::endl; 
     std::cout << sq2::c_str() << std::endl; 
     std::cout << sq3::c_str() << std::endl; 

     typedef concat_seq<std::tuple< sq1, sq2 >>::type str1; 
     typedef concat_seq<std::tuple< str1, sq3 >>::type str2; 


     std::cout << str1::c_str() << std::endl; 
     std::cout << str2::c_str() << std::endl; 


    return 0; 
} 

Это больше, чем нужно. Он инициализирует строки UTF-8 без проблем.

http://coliru.stacked-crooked.com/a/9039c901822fcabc

0

Я нашел более компактный способ достижения конкатенации константных символов во время компиляции, используя импульс. Здесь готов к заголовочный файл StaticString.h:

#include <boost/mpl/vector_c.hpp> 
#include <boost/mpl/back_inserter.hpp> 
#include <boost/preprocessor.hpp> 
#include <boost/mpl/string.hpp> 
#include <boost/mpl/copy_if.hpp> 

template <typename S1, typename S2> 
struct Concatenate { 
    typedef typename boost::mpl::copy_if< 
      S2, 
      boost::mpl::not_< 
       boost::is_same< 
        boost::mpl::_1, 
        boost::mpl::integral_c<char, '\0'>> 
      >, 
      boost::mpl::back_inserter<S1> 
    >::type type; 
}; 

// sink template parameter _ simplifies AT macro 
template<typename _, char ... CHARS> 
struct StaticString { 
private: 
    typedef typename boost::mpl::vector_c<char, CHARS...>::type _input; 
public: 
    // this is needed to remove '\0' from the end of _input 
    typedef typename Concatenate< 
      boost::mpl::vector_c<char>, 
      _input 
    >::type type; 
}; 

#define AT(z, i, data) , i < sizeof(data) ? data[i] : '\0' 
#define _S(s) StaticString<char BOOST_PP_REPEAT(16, AT, s) >::type 

и пример его использования:

#include "StaticString.h" 

#include <iostream> 
using namespace std; 
using boost::mpl::c_str; 
using boost::mpl::size; 

int main() 
{ 
    typedef _S("Hello ") Hello; 
    cout << c_str<Hello>::value << endl; 
    cout << size<Hello>::type::value << endl; 

    typedef _S("World!") World; 
    cout << c_str<World>::value << endl; 
    cout << size<World>::type::value << endl; 

    typedef Concatenate<Hello, World>::type concatenated; 
    cout << c_str<concatenated>::value << endl; 
    cout << size<concatenated>::type::value << endl; 

    return 0; 
} 

Вывод должен быть:

Hello 
6 
World! 
6 
Hello World! 
12 
Смежные вопросы