やーやーやー
なんで私、最近こんな黒魔術に手を出してるんだろうね。最近、相当変態的な方向性でC++を悪用 利用しようと企ててるから、こんな羽目になってますよ。
と言うのもですね、こう、色々と面倒くさい諸問題を回避しようとしてたら、黒い方法を思いついてしまったんだ。いや、私は悪くない。Goサインを出した人が悪いんだ。
しかし、C++11、C++14で相当敷居が下がったって言っても、型だとか、constexprってやっぱり、こう、闇の軍団か中3女子的なイメージあるじゃない。タイトルみたいなことは、Sprout使ったらすぐできそうなんだけど、政治的ごにょごにょにより…
ポンコツ…いや、豚骨な私が手を出して良い領域じゃないと思うんですよ。私はC++を完全に理解した日は来るのだろうか。
闇の軍団的にはできて当たり前なのかも知れないけど、こう、ファイアをやっと唱えられましたレベルの私だと中々ね。
やりたいこと
以下の型を宣言したい。
template<char... chars>struct char_type { static void print(){ (void)std::initializer_list<int>{(void(std::cout << chars),0)...}; std::cout << std::endl; } };
constexprな関数から作る場合
C++14なら豚骨にも簡単にできた。
関数から作ることができるので、constexprな配列の名前が定義されてたら、同じように作ることが可能。
template<int N> struct make_alphabet_type { private: static constexpr char get(int n){return (char)('a'+n);} template<typename Seq>struct make_char_type{}; template<typename I,I... seq>struct make_char_type<std::integer_sequence<I,seq...>>{ using type = char_type<get(seq)...>; }; public: using type =typename make_char_type<std::make_integer_sequence<size_t,N>>::type; }; int main(int argc, char *argv[]) { using a5_t = make_alphabet_type<5>::type; a5_t::print(); // abcdeと出力される return 0; }
実体は何処にもないけど、constexprの計算で作ったchar配列の型を作ることができたよ!
文字列リテラルから作りたい
GCC拡張のtemplateユーザー文字列リテラルが使えるなら簡単なんだけど、これどうすれば良いんだろ。一度どこかに名前を作れれたりすればいいんだけど。ラムダで何とかならないかと思ったけど無理でした。
BOOST_PP_ENUMとか使えばできるっぽいけど。
BOOST_PP_ENUMと同じことを手でやってしまえば、固定長だけど、出来ないことは無くて、しかも私の目的としてはこれで十分なんだけど。
//GCCの場合はこれ template<char... chars> constexpr char_type<chars...> operator ""_chartype(){return char_type<chars...>();} template<char... chars>struct _char_type{ private: static constexpr char str[] = {chars...}; static constexpr size_t array_size = sizeof...(chars); static constexpr size_t count(size_t i){ return i == array_size? array_size: str[i] == '\0' ? i : count(i+1); } static constexpr size_t length = count(0); template<typename seq>struct make_char_type{}; template<typename I,I... seq>struct make_char_type<std::integer_sequence<I,seq...>>{ using type = char_type<str[seq]...>; }; public: using type = typename make_char_type<std::make_integer_sequence<int, length>>::type; }; template<int N> constexpr char get_char(const char (&array)[N],int index){ return index < N? array[index] : '\0'; } #define GET_CHAR_TYPE(x) _char_type<get_char(x,0),get_char(x,1),get_char(x,2),get_char(x,3),get_char(x,4),get_char(x,5),get_char(x,6)>::type int main(int argc, char *argv[]) { using abc_t = GET_CHAR_TYPE("abc"); abc_t::print(); return 0; }