文字列から関数のパラメータ型を推測したい。 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>{});
}
...
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;
}
私が欲しいもの:
は現在、私は次の操作を行います次のようなものです(コンパイル時のチェックのみ):
MyFoo foo("%d Hello World %f %s");
foo.Send(10, 20.f, "Hello");
文字列リテラルからタイプのリストを取得することができ
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...>>>;
};
:
パラメータタイプが文字列の内容に応じて予想されるタイプに対応するかどうかを実行時に確認する必要があります – Garf365
ありがとうございますが、コンパイル時のチェックが必要です。 (質問に追加されました) – Viatorus
MyFooインスタンスのテンプレート引数を取得してメンバSendのパラメータを定義するには、C++メタプログラミングを使用して静的定数文字列を解析する必要があります。しかし、それはバイト単位で、多くのバリエーションと限界をチェックする必要があります。ランタイムバージョンを実装するほうがよいでしょう。 – Youka