方便地在C ++中声明编译时string

在C ++编译期间能够创build和操作string有几个有用的应用程序。 尽pipe可以在C ++中创build编译时string,但是这个过程非常麻烦,因为string需要被声明为可变字符序列,例如

using str = sequence<'H', 'e', 'l', 'l', 'o', ', ', 'w', 'o', 'r', 'l', 'd', '!'>; 

诸如string连接,子串提取等许多操作可以很容易地实现为对字符序列的操作。 是否可以更方便地声明编译时string? 如果不是的话,有没有一个scheme可以方便的声明编译时间string?

为什么现有的方法失败

理想情况下,我们希望能够声明编译时间string如下:

 // Approach 1 using str1 = sequence<"Hello, world!">; 

或者,使用用户定义的文字,

 // Approach 2 constexpr auto str2 = "Hello, world!"_s; 

decltype(str2)将有一个constexpr构造函数。 方法1的一个更复杂的版本可以实现,利用这个事实,你可以做到以下几点:

 template <unsigned Size, const char Array[Size]> struct foo; 

然而,数组需要有外部链接,所以为了让方法1工作,我们必须写这样的东西:

 /* Implementation of array to sequence goes here. */ constexpr const char str[] = "Hello, world!"; int main() { using s = string<13, str>; return 0; } 

不用说,这是非常不方便的。 方法2实际上是不可能实现的。 如果我们要声明一个( constexpr )文字运算符,那么我们将如何指定返回types? 由于我们需要运算符返回一个可变的字符序列,所以我们需要使用const char*参数来指定返回types:

 constexpr auto operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */ 

这会导致编译错误,因为s不是constexpr 。 尝试通过执行以下操作来解决此问题并没有多大帮助。

 template <char... Ts> constexpr sequence<Ts...> operator"" _s() { return {}; } 

该标准规定,这个特定的文字操作符表单是为整数和浮点types保留的。 虽然123_s会工作, abc_s不会。 如果我们完全抛弃用户定义的文字,而只是使用一个常规的constexpr函数呢?

 template <unsigned Size> constexpr auto string(const char (&array)[Size]) -> /* Some metafunction using `array` */ 

和以前一样,我们遇到了这样一个问题,即数组(现在是constexpr函数的一个参数)本身不再是一个constexprtypes。

我相信应该可以定义一个C预处理器macros,它将一个string和string的大小作为参数,并返回一个由string中的字符组成的序列(使用BOOST_PP_FOR ,string化,数组下标等)。 但是,我没有时间(或足够的兴趣)来实现这样一个macros=)

我还没有看到任何与C ++ Now 2012提供的Scott Schurr的str_const的优雅相匹配的东西。 它确实需要constexpr

以下是您如何使用它,以及它可以做什么:

 int main() { constexpr str_const my_string = "Hello, world!"; static_assert(my_string.size() == 13, ""); static_assert(my_string[4] == 'o', ""); constexpr str_const my_other_string = my_string; static_assert(my_string == my_other_string, ""); constexpr str_const world(my_string, 7, 5); static_assert(world == "world", ""); // constexpr char x = world[5]; // Does not compile because index is out of range! } 

它不会比编译时间范围检查更酷!

使用和实现都没有macros。 而且没有人为限制string的大小。 我会在这里发布实施,但我尊重斯科特的隐含版权。 他的演示文稿的一个幻灯片是与上面相关的。

我相信应该可以定义一个C预处理器macros,它将一个string和string的大小作为参数,并返回一个由string中的字符组成的序列(使用BOOST_PP_FOR,string化,数组下标等)。 但是,我没有时间(或者没有足够的兴趣)去实现这样一个macros

使用非常简单的macros和一些C ++ 11特性,可以实现这一点,而不依赖于boost:

  1. lambdas variadic
  2. 模板
  3. 广义常量expression式
  4. 非静态数据成员初始值设定项
  5. 统一初始化

(后两者在这里不是严格要求的)

  1. 我们需要能够实例化用户提供的从0到N的可变参数模板 – 一个工具也可用于将元组展开成可变参数模板函数的参数(请参阅问题: 如何将元组展开为可变参数模板函数的参数?
    “解包”一个元组来调用一个匹配的函数指针 )

     namespace variadic_toolbox { template<unsigned count, template<unsigned...> class meta_functor, unsigned... indices> struct apply_range { typedef typename apply_range<count-1, meta_functor, count-1, indices...>::result result; }; template<template<unsigned...> class meta_functor, unsigned... indices> struct apply_range<0, meta_functor, indices...> { typedef typename meta_functor<indices...>::result result; }; } 
  2. 然后使用非types参数char定义一个名为string的可变参数模板:

     namespace compile_time { template<char... str> struct string { static constexpr const char chars[sizeof...(str)+1] = {str..., '\0'}; }; template<char... str> constexpr const char string<str...>::chars[sizeof...(str)+1]; } 
  3. 现在最有趣的部分 – 将字符文字传递到string模板:

     namespace compile_time { template<typename lambda_str_type> struct string_builder { template<unsigned... indices> struct produce { typedef string<lambda_str_type{}.chars[indices]...> result; }; }; } #define CSTRING(string_literal) \ []{ \ struct constexpr_string_type { const char * chars = string_literal; }; \ return variadic_toolbox::apply_range<sizeof(string_literal)-1, \ compile_time::string_builder<constexpr_string_type>::produce>::result{}; \ }() 

一个简单的连接演示显示用法:

  namespace compile_time { template<char... str0, char... str1> string<str0..., str1...> operator*(string<str0...>, string<str1...>) { return {}; } } int main() { auto str0 = CSTRING("hello"); auto str1 = CSTRING(" world"); std::cout << "runtime concat: " << str_hello.chars << str_world.chars << "\n <=> \n"; std::cout << "compile concat: " << (str_hello * str_world).chars << std::endl; } 

https://ideone.com/8Ft2xu

编辑:作为霍华德Hinnant(和我有些在我的意见,指出),你可能不需要一个types的string的每个单一字符作为单个模板参数。 如果你确实需要这个,下面有一个macros观解决scheme。

我在编译时尝试使用string时发现了一个技巧。 它需要引入除“模板string”之外的另一个types,但在函数内,可以限制此types的范围。

它不使用macros,而是使用一些C ++ 11function。

 #include <iostream> // helper function constexpr unsigned c_strlen( char const* str, unsigned count = 0 ) { return ('\0' == str[0]) ? count : c_strlen(str+1, count+1); } // helper "function" struct template < char t_c, char... tt_c > struct rec_print { static void print() { std::cout << t_c; rec_print < tt_c... > :: print (); } }; template < char t_c > struct rec_print < t_c > { static void print() { std::cout << t_c; } }; // destination "template string" type template < char... tt_c > struct exploded_string { static void print() { rec_print < tt_c... > :: print(); } }; // struct to explode a `char const*` to an `exploded_string` type template < typename T_StrProvider, unsigned t_len, char... tt_c > struct explode_impl { using result = typename explode_impl < T_StrProvider, t_len-1, T_StrProvider::str()[t_len-1], tt_c... > :: result; }; template < typename T_StrProvider, char... tt_c > struct explode_impl < T_StrProvider, 0, tt_c... > { using result = exploded_string < tt_c... >; }; // syntactical sugar template < typename T_StrProvider > using explode = typename explode_impl < T_StrProvider, c_strlen(T_StrProvider::str()) > :: result; int main() { // the trick is to introduce a type which provides the string, rather than // storing the string itself struct my_str_provider { constexpr static char const* str() { return "hello world"; } }; auto my_str = explode < my_str_provider >{}; // as a variable using My_Str = explode < my_str_provider >; // as a type my_str.print(); } 

如果你不想使用Boost解决scheme,你可以创build一个简单的macros来做类似的事情:

 #define MACRO_GET_1(str, i) \ (sizeof(str) > (i) ? str[(i)] : 0) #define MACRO_GET_4(str, i) \ MACRO_GET_1(str, i+0), \ MACRO_GET_1(str, i+1), \ MACRO_GET_1(str, i+2), \ MACRO_GET_1(str, i+3) #define MACRO_GET_16(str, i) \ MACRO_GET_4(str, i+0), \ MACRO_GET_4(str, i+4), \ MACRO_GET_4(str, i+8), \ MACRO_GET_4(str, i+12) #define MACRO_GET_64(str, i) \ MACRO_GET_16(str, i+0), \ MACRO_GET_16(str, i+16), \ MACRO_GET_16(str, i+32), \ MACRO_GET_16(str, i+48) #define MACRO_GET_STR(str) MACRO_GET_64(str, 0), 0 //guard for longer strings using seq = sequence<MACRO_GET_STR("Hello world!")>; 

唯一的问题是固定大小的64个字符(加上额外的零)。 但可以根据您的需要轻松更改。

我相信应该可以定义一个C预处理器macros,它将一个string和string的大小作为参数,并返回一个由string中的字符组成的序列(使用BOOST_PP_FOR,string化,数组下标等)

有文章: 在 Abel Sinkovics和Dave Abrahams的C ++模板元程序中使用string 。

与使用macros+ BOOST_PP_REPEAT的想法相比,它有一些改进 – 它不需要将显式大小传递给macros。 总之,它是以固定的绳子尺寸上限和“绳子超限保护”为基础的:

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

加上条件boost :: mpl :: push_back


我把我接受的答案改为Yankes的解决scheme,因为它解决了这个特定的问题,而且没有使用constexpr或者复杂的预处理器代码就可以优雅地完成。

如果你接受尾随零,手写macros循环,扩展macros中的string重复2次 ,并没有提升 – 那么我同意 – 这是更好的。 虽然,提升只有三行:

现场演示

 #include <boost/preprocessor/repetition/repeat.hpp> #define GET_STR_AUX(_, i, str) (sizeof(str) > (i) ? str[(i)] : 0), #define GET_STR(str) BOOST_PP_REPEAT(64,GET_STR_AUX,str) 0 

一位同事质疑我在编译时连接内存中的string。 它包括在编译时实例化单个string。 完整的代码清单在这里:

 //Arrange strings contiguously in memory at compile-time from string literals. //All free functions prefixed with "my" to faciliate grepping the symbol tree //(none of them should show up). #include <iostream> using std::size_t; //wrapper for const char* to "allocate" space for it at compile-time template<size_t N> struct String { //C arrays can only be initialised with a comma-delimited list //of values in curly braces. Good thing the compiler expands //parameter packs into comma-delimited lists. Now we just have //to get a parameter pack of char into the constructor. template<typename... Args> constexpr String(Args... args):_str{ args... } { } const char _str[N]; }; //takes variadic number of chars, creates String object from it. //ie myMakeStringFromChars('f', 'o', 'o', '\0') -> String<4>::_str = "foo" template<typename... Args> constexpr auto myMakeStringFromChars(Args... args) -> String<sizeof...(Args)> { return String<sizeof...(args)>(args...); } //This struct is here just because the iteration is going up instead of //down. The solution was to mix traditional template metaprogramming //with constexpr to be able to terminate the recursion since the template //parameter N is needed in order to return the right-sized String<N>. //This class exists only to dispatch on the recursion being finished or not. //The default below continues recursion. template<bool TERMINATE> struct RecurseOrStop { template<size_t N, size_t I, typename... Args> static constexpr String<N> recurseOrStop(const char* str, Args... args); }; //Specialisation to terminate recursion when all characters have been //stripped from the string and converted to a variadic template parameter pack. template<> struct RecurseOrStop<true> { template<size_t N, size_t I, typename... Args> static constexpr String<N> recurseOrStop(const char* str, Args... args); }; //Actual function to recurse over the string and turn it into a variadic //parameter list of characters. //Named differently to avoid infinite recursion. template<size_t N, size_t I = 0, typename... Args> constexpr String<N> myRecurseOrStop(const char* str, Args... args) { //template needed after :: since the compiler needs to distinguish //between recurseOrStop being a function template with 2 paramaters //or an enum being compared to N (recurseOrStop < N) return RecurseOrStop<I == N>::template recurseOrStop<N, I>(str, args...); } //implementation of the declaration above //add a character to the end of the parameter pack and recurse to next character. template<bool TERMINATE> template<size_t N, size_t I, typename... Args> constexpr String<N> RecurseOrStop<TERMINATE>::recurseOrStop(const char* str, Args... args) { return myRecurseOrStop<N, I + 1>(str, args..., str[I]); } //implementation of the declaration above //terminate recursion and construct string from full list of characters. template<size_t N, size_t I, typename... Args> constexpr String<N> RecurseOrStop<true>::recurseOrStop(const char* str, Args... args) { return myMakeStringFromChars(args...); } //takes a compile-time static string literal and returns String<N> from it //this happens by transforming the string literal into a variadic paramater //pack of char. //ie myMakeString("foo") -> calls myMakeStringFromChars('f', 'o', 'o', '\0'); template<size_t N> constexpr String<N> myMakeString(const char (&str)[N]) { return myRecurseOrStop<N>(str); } //Simple tuple implementation. The only reason std::tuple isn't being used //is because its only constexpr constructor is the default constructor. //We need a constexpr constructor to be able to do compile-time shenanigans, //and it's easier to roll our own tuple than to edit the standard library code. //use MyTupleLeaf to construct MyTuple and make sure the order in memory //is the same as the order of the variadic parameter pack passed to MyTuple. template<typename T> struct MyTupleLeaf { constexpr MyTupleLeaf(T value):_value(value) { } T _value; }; //Use MyTupleLeaf implementation to define MyTuple. //Won't work if used with 2 String<> objects of the same size but this //is just a toy implementation anyway. Multiple inheritance guarantees //data in the same order in memory as the variadic parameters. template<typename... Args> struct MyTuple: public MyTupleLeaf<Args>... { constexpr MyTuple(Args... args):MyTupleLeaf<Args>(args)... { } }; //Helper function akin to std::make_tuple. Needed since functions can deduce //types from parameter values, but classes can't. template<typename... Args> constexpr MyTuple<Args...> myMakeTuple(Args... args) { return MyTuple<Args...>(args...); } //Takes a variadic list of string literals and returns a tuple of String<> objects. //These will be contiguous in memory. Trailing '\0' adds 1 to the size of each string. //ie ("foo", "foobar") -> (const char (&arg1)[4], const char (&arg2)[7]) params -> // -> MyTuple<String<4>, String<7>> return value template<size_t... Sizes> constexpr auto myMakeStrings(const char (&...args)[Sizes]) -> MyTuple<String<Sizes>...> { //expands into myMakeTuple(myMakeString(arg1), myMakeString(arg2), ...) return myMakeTuple(myMakeString(args)...); } //Prints tuple of strings template<typename T> //just to avoid typing the tuple type of the strings param void printStrings(const T& strings) { //No std::get or any other helpers for MyTuple, so intead just cast it to //const char* to explore its layout in memory. We could add iterators to //myTuple and do "for(auto data: strings)" for ease of use, but the whole //point of this exercise is the memory layout and nothing makes that clearer //than the ugly cast below. const char* const chars = reinterpret_cast<const char*>(&strings); std::cout << "Printing strings of total size " << sizeof(strings); std::cout << " bytes:\n"; std::cout << "-------------------------------\n"; for(size_t i = 0; i < sizeof(strings); ++i) { chars[i] == '\0' ? std::cout << "\n" : std::cout << chars[i]; } std::cout << "-------------------------------\n"; std::cout << "\n\n"; } int main() { { constexpr auto strings = myMakeStrings("foo", "foobar", "strings at compile time"); printStrings(strings); } { constexpr auto strings = myMakeStrings("Some more strings", "just to show Jeff to not try", "to challenge C++11 again :P", "with more", "to show this is variadic"); printStrings(strings); } std::cout << "Running 'objdump -t |grep my' should show that none of the\n"; std::cout << "functions defined in this file (except printStrings()) are in\n"; std::cout << "the executable. All computations are done by the compiler at\n"; std::cout << "compile-time. printStrings() executes at run-time.\n"; } 

基于Howard Hinnant的想法,你可以创build一个将两个文字加在一起的文字类。

 template<int> using charDummy = char; template<int... dummy> struct F { const char table[sizeof...(dummy) + 1]; constexpr F(const char* a) : table{ str_at<dummy>(a)..., 0} { } constexpr F(charDummy<dummy>... a) : table{ a..., 0} { } constexpr F(const F& a) : table{ a.table[dummy]..., 0} { } template<int... dummyB> constexpr F<dummy..., sizeof...(dummy)+dummyB...> operator+(F<dummyB...> b) { return { this->table[dummy]..., b.table[dummyB]... }; } }; template<int I> struct get_string { constexpr static auto g(const char* a) -> decltype( get_string<I-1>::g(a) + F<0>(a + I)) { return get_string<I-1>::g(a) + F<0>(a + I); } }; template<> struct get_string<0> { constexpr static F<0> g(const char* a) { return {a}; } }; template<int I> constexpr auto make_string(const char (&a)[I]) -> decltype( get_string<I-2>::g(a) ) { return get_string<I-2>::g(a); } constexpr auto a = make_string("abc"); constexpr auto b = a+ make_string("def"); // b.table == "abcdef" 

这是一个简洁的C ++ 14解决scheme,为每个传递的编译时string创build一个std :: tuple <char …>。

 #include <tuple> #include <utility> namespace detail { template <std::size_t ... indices> decltype(auto) build_string(const char * str, std::index_sequence<indices...>) { return std::make_tuple(str[indices]...); } } template <std::size_t N> constexpr decltype(auto) make_string(const char(&str)[N]) { return detail::build_string(str, std::make_index_sequence<N>()); } auto HelloStrObject = make_string("hello"); 

这里有一个用于创build一个独特的编译时types,从另一个macros文章中删减。

 #include <utility> template <char ... Chars> struct String {}; template <typename Str, std::size_t ... indices> decltype(auto) build_string(std::index_sequence<indices...>) { return String<Str().chars[indices]...>(); } #define make_string(str) []{\ struct Str { const char * chars = str; };\ return build_string<Str>(std::make_index_sequence<sizeof(str)>());\ }() auto HelloStrObject = make_string("hello"); 

用户定义的字面值不能用于这个真的太糟糕了。

似乎没有人喜欢我的其他答案: – <。 所以在这里我展示了如何将一个str_const转换为一个真正的types:

 #include <iostream> #include <utility> // constexpr string with const member functions class str_const { private: const char* const p_; const std::size_t sz_; public: template<std::size_t N> constexpr str_const(const char(&a)[N]) : // ctor p_(a), sz_(N-1) {} constexpr char operator[](std::size_t n) const { return n < sz_ ? p_[n] : throw std::out_of_range(""); } constexpr std::size_t size() const { return sz_; } // size() }; template <char... letters> struct string_t{ static char const * c_str() { static constexpr char string[]={letters...,'\0'}; return string; } }; template<str_const const& str,std::size_t... I> auto constexpr expand(std::index_sequence<I...>){ return string_t<str[I]...>{}; } template<str_const const& str> using string_const_to_type = decltype(expand<str>(std::make_index_sequence<str.size()>{})); constexpr str_const hello{"Hello World"}; using hello_t = string_const_to_type<hello>; int main() { // char c = hello_t{}; // Compile error to print type std::cout << hello_t::c_str(); return 0; } 

用clang编译++ -stdlib = libc ++ -std = c ++ 14(clang 3.7)

用于创build独特编译时types的凯西解决scheme只需稍作修改即可用于C ++ 11:

 template <char... Chars> struct string_t {}; namespace detail { template <typename Str,unsigned int N,char... Chars> struct make_string_t : make_string_t<Str,N-1,Str().chars[N-1],Chars...> {}; template <typename Str,char... Chars> struct make_string_t<Str,0,Chars...> { typedef string_t<Chars...> type; }; } // namespace detail #define CSTR(str) []{ \ struct Str { const char *chars = str; }; \ return detail::make_string_t<Str,sizeof(str)>::type(); \ }() 

使用:

 template <typename String> void test(String) { // ... String = string_t<'H','e','l','l','o','\0'> } test(CSTR("Hello")); 

你的方法#1是正确的。

然而,数组需要有外部链接,所以为了得到方法1的工作,我们必须写这样的:constexpr const char str [] =“Hello,world!”;

不,不正确 这与编译和gcc。 我希望它的标准C ++ 11,但我不是一个语言的水平。

 #include <iostream> template <char... letters> struct string_t{ static char const * c_str() { static constexpr char string[]={letters...,'\0'}; return string; } }; // just live with it, but only once using Hello_World_t = string_t<'H','e','l','l','o',' ','w','o','r','l','d','!'>; template <typename Name> void print() { //String as template parameter std::cout << Name::c_str(); } int main() { std::cout << Hello_World_t::c_str() << std::endl; print<Hello_World_t>(); return 0; } 

我真正爱c ++ 17将是以下相当(完成方法#1)

 // for template <char...> <"Text"> == <'T','e','x','t'> 

在模板用户定义文字的标准中已经存在非常类似的东西,因为void-pointer也提到了,但仅限于数字。 到那时另外一个小窍门就是使用覆盖编辑模式+复制粘贴了

 string_t<' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '>; 

如果你不介意这个macros,比这个作品(从Yankes回答略微修改):

 #define MACRO_GET_1(str, i) \ (sizeof(str) > (i) ? str[(i)] : 0) #define MACRO_GET_4(str, i) \ MACRO_GET_1(str, i+0), \ MACRO_GET_1(str, i+1), \ MACRO_GET_1(str, i+2), \ MACRO_GET_1(str, i+3) #define MACRO_GET_16(str, i) \ MACRO_GET_4(str, i+0), \ MACRO_GET_4(str, i+4), \ MACRO_GET_4(str, i+8), \ MACRO_GET_4(str, i+12) #define MACRO_GET_64(str, i) \ MACRO_GET_16(str, i+0), \ MACRO_GET_16(str, i+16), \ MACRO_GET_16(str, i+32), \ MACRO_GET_16(str, i+48) //CT_STR means Compile-Time_String #define CT_STR(str) string_t<MACRO_GET_64(#str, 0), 0 >//guard for longer strings print<CT_STR(Hello World!)>(); 

在玩助推器的时候,我碰到了这个线程。 由于没有答案解决了我的问题,我发现了一个不同的解决scheme,我想在这里添加,因为它可能会对其他人有帮助。

我的问题是,当与hanastring一起使用boost hana map时,编译器仍然生成一些运行时代码(见下文)。 原因很明显,在编译时查询地图一定要加以解决。 这是不可能的,因为BOOST_HANA_STRINGmacros生成一个lambdaexpression式,不能在constexpr上下文中使用。 另一方面,地图需要不同内容的string为不同的types。

As the solutions in this thread are either using a lambda or not providing different types for different contents, I found the following approach helpful. Also it avoids the hacky str<'a', 'b', 'c'> syntax.

The basic idea is having a version of Scott Schurr's str_const templated on the hash of the characters. It is c++14 , but c++11 should be possible with a recursive implementation of the crc32 function (see here ).

 // str_const from https://github.com/boostcon/cppnow_presentations_2012/blob/master/wed/schurr_cpp11_tools_for_class_authors.pdf?raw=true #include <string> template<unsigned Hash> ////// <- This is the difference... class str_const2 { // constexpr string private: const char* const p_; const std::size_t sz_; public: template<std::size_t N> constexpr str_const2(const char(&a)[N]) : // ctor p_(a), sz_(N - 1) {} constexpr char operator[](std::size_t n) const { // [] return n < sz_ ? p_[n] : throw std::out_of_range(""); } constexpr std::size_t size() const { return sz_; } // size() constexpr const char* const data() const { return p_; } }; // Crc32 hash function. Non-recursive version of https://stackoverflow.com/a/23683218/8494588 static constexpr unsigned int crc_table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; template<size_t N> constexpr auto crc32(const char(&str)[N]) { unsigned int prev_crc = 0xFFFFFFFF; for (auto idx = 0; idx < sizeof(str) - 1; ++idx) prev_crc = (prev_crc >> 8) ^ crc_table[(prev_crc ^ str[idx]) & 0xFF]; return prev_crc ^ 0xFFFFFFFF; } // Conveniently create a str_const2 #define CSTRING(text) str_const2 < crc32( text ) >( text ) // Conveniently create a hana type_c<str_const2> for use in map #define CSTRING_TYPE(text) hana::type_c<decltype(str_const2 < crc32( text ) >( text ))> 

用法:

 #include <boost/hana.hpp> #include <boost/hana/map.hpp> #include <boost/hana/pair.hpp> #include <boost/hana/type.hpp> namespace hana = boost::hana; int main() { constexpr auto s2 = CSTRING("blah"); constexpr auto X = hana::make_map( hana::make_pair(CSTRING_TYPE("aa"), 1) ); constexpr auto X2 = hana::insert(X, hana::make_pair(CSTRING_TYPE("aab"), 2)); constexpr auto ret = X2[(CSTRING_TYPE("aab"))]; return ret; } 

Resulting assembler code with clang-cl 5.0 is:

 012A1370 mov eax,2 012A1375 ret