从文字字符串中推断类型

Via*_*rus 8 c++ variadic-templates c++11 c++14

我想从字符串中推断出函数的参数类型.类似于printf所做的.

目前我做以下事情:

#include <utility>

// calculate the length of a 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;
};

// Get type from 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;
};

// My dummy class
template <typename... Targs>
struct Foo
{
    void Send(Targs...) const {}
};

// Deduce type for 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>{});
}
Run Code Online (Sandbox Code Playgroud)

问题是,我必须在函数调用上写Ignore()...

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;
}
Run Code Online (Sandbox Code Playgroud)

实例

我想要的是像(仅编译时检查):

MyFoo foo("%d Hello World %f %s");
foo.Send(10, 20.f, "Hello");
Run Code Online (Sandbox Code Playgroud)

Via*_*rus 1

我的最新版本:适用于 C++11、GCC 4.8 和 Clang。其他未测试。

/*!
 * @brief Variadic template contains all parsed types.
 */
template <typename ...T>
struct TypeHolder
{
};

/*!
 * @brief Identifier for non formating sequence.
 */
struct Unknown {};

/*!
 * @brief Identifier for possible formating sequence.
 */
struct Formater {};

/*!
 * @brief Any character.
 */
template <char C, typename TYPE, const char *STR, int POS, typename...T>
struct Format
{
    using type = typename Format<STR[POS], Unknown, STR, POS + 1, T...>::type;
};

/*!
 * @brief Null-terminator.
 */
template <const char *STR, typename TYPE, int POS, typename...T>
struct Format<'\0', TYPE, STR, POS, T...> {

    using type = TypeHolder<T...>;
};

/*!
 * @brief Indicates a formation.
 */
template <const char *STR, int POS, typename...T>
struct Format<'%', Unknown, STR, POS, T...> {

    using type = typename Format<STR[POS], Formater, STR, POS + 1, T...>::type;
};

/*!
 * @brief Formation was a escape sequence for %.
 */
template <const char *STR, int POS, typename...T>
struct Format<'%', Formater, STR, POS, T...> {
    using type = typename Format<STR[POS], Unknown, STR, POS + 1, T...>::type;
};

/*!
 * @brief Formation of an integer.
 */
template <const char *STR, int POS, typename...T>
struct Format<'d', Formater, STR, POS, T...> {
    // Append int to variadic template.
    using type = typename Format<STR[POS], Unknown, STR, POS + 1, T..., int>::type;
};

/*!
 * @brief Formation of an unsigned integer.
 */
template <const char *STR, int POS, typename...T>
struct Format<'u', Formater, STR, POS, T...> {
    // Append unsigned int to variadic template.
    using type = typename Format<STR[POS], Unknown, STR, POS + 1, T..., unsigned int>::type;
};

/*!
 * @brief Formation of a float.
 */
template <const char *STR, int POS, typename...T>
struct Format<'f', Formater, STR, POS, T...> {
    // Append float to variadic template.
    using type = typename Format<STR[POS], Unknown, STR, POS + 1, T..., float>::type;
};

/*!
 * @brief Unknown formatting.
 */
template <char C, const char *STR, int POS, typename...T>
struct Format<C, Formater, STR, POS, T...> {
    // Compile time error for unknown formatting.
    static_assert(sizeof...(T) != sizeof...(T), "Unknown formattion.");
    using type = TypeHolder<>;
};

/*!
 * @brief
 */
template <const char *STR>
struct GetTypeFromString {
  using type = typename Format<STR[0], Unknown, STR, 1>::type;
};

template<typename>
class Foo;

template<typename... Ts>
struct Foo<TypeHolder<Ts...>>
{
    void call(Ts...) const {

    }
};

constexpr const char message[] = " %d %u %% Hello World %d %f";
constexpr auto foo = Foo<GetTypeFromString<message>::type>();

int main() {

    foo.call(int(), int(), int(), float());

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

实例

感谢您的帮助!

有什么优化吗?