如何在编译时连接const char *

时间:2014-01-07 06:07:08

标签: c++ c++11 boost-mpl

我有一个mpl :: string的向量。 mpl :: string size limit是32个元素。有一种方法可以在编译时创建const char *数组

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

但是我需要在编译时获得一个const char *字符串。怎么做?

更新 我在编译时创建了一个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”中的“string”如何?

3 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分: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

答案 2 :(得分:0)

我发现使用boost在编译时实现连续const字符的更简洁方法。这里准备好去头文件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