c++ - 从文字字符串推断类型

标签 c++ c++11 c++14 variadic-templates

我想从字符串中推断出函数的参数类型。类似于 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>{});
}

问题是,我必须在我的函数调用中编写 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;
}

Live Example

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

MyFoo foo("%d Hello World %f %s");
foo.Send(10, 20.f, "Hello");

最佳答案

你可以用 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");
};

// %% for %
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...>>>;
};

允许从文字字符串中检索类型列表。

然后

// ...

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);
}

Demo

关于c++ - 从文字字符串推断类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36056710/

相关文章:

c++ - 如何创建一个以字符作为键值并将字符串数组作为映射值的映射 - 数组必须具有不同的长度?

c++ - 通过指针读取文件

c++ - 类内的回调函数

c++ - 为什么我的模板参数包不起作用?

c++ - C++ 中的动态对象?

c++ - 如何找到继承类的分配地址

c++ - C++11、14、17 或 20 是否为 pi 引入了标准常量?

c++ - make_heap 不堆

c++ - 可组合的 C++ 函数装饰器

c++ - N3797 的§8.5 p17(初始值设定项的语义)中是否缺少案例?