c++ - Deduce type from literal string -
i want deduce parameter types of function string. similar printf does.
currently following:
#include <utility> // calculate length of literal string constexpr int length(const char* str) { return *str ? 1 + length(str + 1) : 0; } struct ignore { }; template <char c1, char c2> struct type { typedef ignore type; }; // %d -> int template <> struct type<'%','d'> { typedef int type; }; // %f -> float template <> struct type<'%','f'> { typedef float type; }; // type string template <const char * const * const str, int pos, int n = length(str[pos])> struct gettype { typedef ignore type; }; template <const char * const * const str, int pos> struct gettype<str, pos, 2> { typedef typename type<str[pos][0],str[pos][1]>::type type; }; // dummy class template <typename... targs> struct foo { void send(targs...) const {} }; // deduce type each literal string array template <const char * const * strs, std::size_t n, std::size_t... index> constexpr auto parseit(std::index_sequence<index...>) { return foo<typename gettype<strs, index>::type...>(); } template <const char * const * strs, std::size_t n> constexpr auto makefoo(const char * const (&a)[n]) { return parseit<strs, 2>(std::make_index_sequence<n>{}); }
the problem is, have write ignore() on function call...
constexpr const char *message[] = {"%d", " hello ", "%f", "good"}; constexpr auto foo = makefoo<message>(message); int main() { foo .send(10, ignore(), 20.0f, ignore()); return 0; }
what want (compile-time check only):
myfoo foo("%d hello world %f %s"); foo.send(10, 20.f, "hello");
you may char_sequence
:
template <char ... > struct char_sequence {}; template <typename ... tuples> using tuple_concat = decltype(std::tuple_cat(std::declval<tuples>()...)); template <typename> struct format_helper; template <typename t> using format_helper_t = typename format_helper<t>::type; // end case template <> struct format_helper<char_sequence<>> { using type = std::tuple<>; }; // general case template <char c, char...cs> struct format_helper<char_sequence<c, cs...>> { using type = format_helper_t<char_sequence<cs...>>; }; template <typename t> struct dependant_false : std::false_type {}; // unknown format % template <char...cs> struct format_helper<char_sequence<'%', cs...>> { static_assert(dependant_false<char_sequence<cs...>>::value, "unsupported escape"); }; // %% % template <char...cs> struct format_helper<char_sequence<'%', '%', cs...>> { using type = format_helper_t<char_sequence<cs...>>; }; // %f float template <char...cs> struct format_helper<char_sequence<'%', 'f', cs...>> { using type = tuple_concat<std::tuple<float>, format_helper_t<char_sequence<cs...>>>; }; // %d int template <char...cs> struct format_helper<char_sequence<'%', 'd', cs...>> { using type = tuple_concat<std::tuple<int>, format_helper_t<char_sequence<cs...>>>; };
that allow retrieve list of type literal string.
and then
// ... template <typename... ts> struct foo { // ... void send(ts... args) const; }; template <typename t> struct tag{}; template <typename... ts> foo<ts...> makefoo(tag<std::tuple<ts...>>, const std::string& s) { return foo<ts...>(s); } template <char ... cs> auto makefoo(char_sequence<cs...>) { const char s[] = {cs..., '\0'}; return makefoo(tag<format_helper_t<char_sequence<cs...>>>{}, s); }
Comments
Post a Comment