文字列リテラルを型の世界へ!
以下のようなことを可能にします。
string_test.cpp
#include <iostream> #include "./string.hpp" template <class> struct print; template <char ...String> struct print<udon::string<String...>> { void operator()() const { char const s[] = { String..., 0 }; std::cout << s << std::endl; } }; int main() { print< // 文字列リテラルを型に変換する UDON_STRING("Hello, world!") > const hello = {}; hello(); }
実行結果
Hello, world!
実装は以下の通りです。
string.hpp
#ifndef UDON_STRING_HPP #define UDON_STRING_HPP #include <cstddef> #include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/facilities/intercept.hpp> #include <boost/preprocessor/iteration/local.hpp> #if !defined(UDON_STRING_SIZE) #define UDON_STRING_SIZE 32 #endif namespace udon { template <char ...> struct string {}; template <BOOST_PP_ENUM_BINARY_PARAMS(UDON_STRING_SIZE, char c, = '\0' BOOST_PP_INTERCEPT)> struct make_string { typedef string<BOOST_PP_ENUM_PARAMS(UDON_STRING_SIZE, c)> type; }; #define BOOST_PP_LOCAL_MACRO(n) \ template <BOOST_PP_ENUM_PARAMS(n, char c)> \ struct make_string<BOOST_PP_ENUM_PARAMS(n, c)> \ { \ typedef string<BOOST_PP_ENUM_PARAMS(n, c)> type; \ }; \ /**/ #define BOOST_PP_LOCAL_LIMITS (0, UDON_STRING_SIZE - 1) #include BOOST_PP_LOCAL_ITERATE() template <std::size_t N> constexpr char at(std::size_t n, char const (&s)[N]) { return n < N ? s[n] : 0; } } #define UDON_STRING_AT(z, n, lit) \ ::udon::at(n, lit) \ /**/ #define UDON_STRING(lit) \ ::udon::make_string<BOOST_PP_ENUM(UDON_STRING_SIZE, UDON_STRING_AT, lit)>::type \ /**/ #endif
見ての通り、constexpr を使って何とかしています。文字数に制限がつくのが美しくありませんね。
追記 (6/2)
constexpr 関数を使わずに、次のように書くこともできます。
#define UDON_STRING_AT(z, n, lit) \ n < sizeof(lit) ? lit[n] : '\0' \ /**/
Constant expression の要件 (FDIS 5.19) は満たしています。GCC 4.6 以降で動作します。