在编译时生成简单格式字符串

发布于 2025-01-19 12:39:28 字数 2316 浏览 1 评论 0原文

我试图在编译时为 fmt 生成一个简单的格式字符串,但我无法完全弄清楚字符串连接。我仅限于 c++ 14。

我想要的是能够为 N 个项目生成格式字符串,因此可以按如下方式使用它: auto my_string = fmt::format(format_string_struct<2>::format_string, "Item", "key1", "value1", "key2", "value2");

生成的格式字符串将为:“{} {}={} {}={}”,生成“Item key1=value1 key2=value2”的格式化字符串。格式字符串的基础是“{}”,并且它为每个 N 附加一个“{}={}”。

我正在尝试使用递归模板,但我无法完全让一切正常工作。我从 连接编译时字符串中得到了一些代码编译时的模板? 用于连接字符串(尽管我得到了对 `concat_impl<&base_format_string_struct::format_string 的 未定义引用, std::integer_sequence, &format_string_parameter_struct::parameter_string, std::integer_sequence>::value'错误)

template<int...I> using is      = std::integer_sequence<int,I...>;
template<int N>   using make_is = std::make_integer_sequence<int,N>;

constexpr auto size(const char*s) { int i = 0; while(*s!=0){++i;++s;} return i; }

template<const char*, typename, const char*, typename>
struct concat_impl;

template<const char* S1, int... I1, const char* S2, int... I2>
struct concat_impl<S1, is<I1...>, S2, is<I2...>> {
    static constexpr const char value[]
    {
        S1[I1]..., S2[I2]..., 0
    };
};

template<const char* S1, const char* S2>
constexpr auto concat {
    concat_impl<S1, make_is<size(S1)>, S2, make_is<size(S2)>>::value
};

struct base_format_string_struct {
    static constexpr const char format_string[] = "{}";    
};

struct format_string_parameter_struct {
    static constexpr const char parameter_string[] = " {}=\"{}\"";
};

template <int arg_count, const char[]... params>
struct format_string_struct:
    public format_string_struct<arg_count - 1, format_string_parameter_struct, params...> {
};

template <int arg_count>
struct format_string_struct:
    public format_string_struct<arg_count - 1, format_string_parameter_struct> {
};

template <const char[]... params>
struct format_string_struct<0> {
  static const char* format_string() {
    return concat<base_format_string_struct, params...>;
  }
};


I'm trying to generate a simple format string for fmt at compile time, but I can't quite figure out the string concatenation. I'm limited to c++ 14.

What I'd like is to be able to generate a format string for N items, so it could be used as follows:
auto my_string = fmt::format(format_string_struct<2>::format_string, "Item", "key1", "value1", "key2", "value2");

The generated format string would be: "{} {}={} {}={}", resulting in a formatted string of "Item key1=value1 key2=value2". The base of the format string would be "{}", and it appends a " {}={}" for each N.

I'm trying to use recursive templates, but I just can't quite get everything to work. I got some code from Concatenate compile-time strings in a template at compile time? for concatenating strings (though I get a undefined reference to `concat_impl<&base_format_string_struct::format_string, std::integer_sequence<int, 0, 1>, &format_string_parameter_struct::parameter_string, std::integer_sequence<int, 0, 1, 2, 3, 4, 5, 6, 7> >::value' error)

template<int...I> using is      = std::integer_sequence<int,I...>;
template<int N>   using make_is = std::make_integer_sequence<int,N>;

constexpr auto size(const char*s) { int i = 0; while(*s!=0){++i;++s;} return i; }

template<const char*, typename, const char*, typename>
struct concat_impl;

template<const char* S1, int... I1, const char* S2, int... I2>
struct concat_impl<S1, is<I1...>, S2, is<I2...>> {
    static constexpr const char value[]
    {
        S1[I1]..., S2[I2]..., 0
    };
};

template<const char* S1, const char* S2>
constexpr auto concat {
    concat_impl<S1, make_is<size(S1)>, S2, make_is<size(S2)>>::value
};

struct base_format_string_struct {
    static constexpr const char format_string[] = "{}";    
};

struct format_string_parameter_struct {
    static constexpr const char parameter_string[] = " {}=\"{}\"";
};

template <int arg_count, const char[]... params>
struct format_string_struct:
    public format_string_struct<arg_count - 1, format_string_parameter_struct, params...> {
};

template <int arg_count>
struct format_string_struct:
    public format_string_struct<arg_count - 1, format_string_parameter_struct> {
};

template <const char[]... params>
struct format_string_struct<0> {
  static const char* format_string() {
    return concat<base_format_string_struct, params...>;
  }
};


如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

江南烟雨〆相思醉 2025-01-26 12:39:28

您有几个错别字(限制为2个参数)。

template<int...I> using is      = std::integer_sequence<int,I...>;
template<int N>   using make_is = std::make_integer_sequence<int,N>;

constexpr auto size(const char*s) { int i = 0; while(*s!=0){++i;++s;} return i; }

template<const char*, typename, const char*, typename>
struct concat_impl;

template<const char* S1, int... I1, const char* S2, int... I2>
struct concat_impl<S1, is<I1...>, S2, is<I2...>> {
    static constexpr const char value[]
    {
        S1[I1]..., S2[I2]..., 0
    };
};

template<const char* S1, const char* S2, const char*... Ss>
struct concat
{
    constexpr static const char* value = concat_impl<S1, make_is<size(S1)>, concat<S2, Ss...>::value, make_is<size(concat<S2, Ss...>::value)>>::value;
};

template<const char* S1, const char* S2>
struct concat<S1, S2>
{
    constexpr static const char* value = concat_impl<S1, make_is<size(S1)>, S2, make_is<size(S2)>>::value;
};

struct base_format_string_struct {
    static constexpr const char format_string[] = "{}";    
};

struct format_string_parameter_struct {
    static constexpr const char parameter_string[] = " {}=\"{}\"";
};

template <int arg_count, const char*... params>
struct format_string_struct:
    public format_string_struct<arg_count - 1, format_string_parameter_struct::parameter_string, params...> {
};

template <int arg_count>
struct format_string_struct<arg_count>:
    public format_string_struct<arg_count - 1, format_string_parameter_struct::parameter_string> {
};

template <const char*... params>
struct format_string_struct<0, params...> {
  static const char* format_string() {
    return concat<base_format_string_struct::format_string, params...>::value;
  }
};

demo

,但我可能会使用constexpr函数:

#if 1 // missing some constexpr for std::array/std::copy

template <typename T, std::size_t N>
struct my_array
{
    T data[N];
};

template <typename CIT, typename IT>
constexpr void copy(CIT begin, CIT end, IT dest)
{
    for (CIT it = begin; it != end; ++it)
    {
        *dest = *it;
        ++dest;
    }
}
#endif

template <std::size_t N>
constexpr my_array<char, 2 + 8 * N + 1> format_string_struct_impl()
{
    my_array<char, 2 + 8 * N + 1> res{};
    constexpr char init[] = "{}"; // size == 2
    constexpr char extra[] = R"( {}="{}")"; // size == 8
    copy(init, init + 2, res.data);
    for (std::size_t i = 0; i != N; ++i) {
        copy(extra, extra + 8, res.data + 2 + i * 8);
    }
    return res;
}

template <std::size_t N>
constexpr my_array<char, 2 + 8 * N + 1> format_string_struct()
{
    // Ensure the computation is done compile time.
    constexpr auto res = format_string_struct_impl<N>();
    return res;
}

demo

You have several typos (and a concat limited to 2 argument).

template<int...I> using is      = std::integer_sequence<int,I...>;
template<int N>   using make_is = std::make_integer_sequence<int,N>;

constexpr auto size(const char*s) { int i = 0; while(*s!=0){++i;++s;} return i; }

template<const char*, typename, const char*, typename>
struct concat_impl;

template<const char* S1, int... I1, const char* S2, int... I2>
struct concat_impl<S1, is<I1...>, S2, is<I2...>> {
    static constexpr const char value[]
    {
        S1[I1]..., S2[I2]..., 0
    };
};

template<const char* S1, const char* S2, const char*... Ss>
struct concat
{
    constexpr static const char* value = concat_impl<S1, make_is<size(S1)>, concat<S2, Ss...>::value, make_is<size(concat<S2, Ss...>::value)>>::value;
};

template<const char* S1, const char* S2>
struct concat<S1, S2>
{
    constexpr static const char* value = concat_impl<S1, make_is<size(S1)>, S2, make_is<size(S2)>>::value;
};

struct base_format_string_struct {
    static constexpr const char format_string[] = "{}";    
};

struct format_string_parameter_struct {
    static constexpr const char parameter_string[] = " {}=\"{}\"";
};

template <int arg_count, const char*... params>
struct format_string_struct:
    public format_string_struct<arg_count - 1, format_string_parameter_struct::parameter_string, params...> {
};

template <int arg_count>
struct format_string_struct<arg_count>:
    public format_string_struct<arg_count - 1, format_string_parameter_struct::parameter_string> {
};

template <const char*... params>
struct format_string_struct<0, params...> {
  static const char* format_string() {
    return concat<base_format_string_struct::format_string, params...>::value;
  }
};

Demo

But I would probably go with constexpr functions:

#if 1 // missing some constexpr for std::array/std::copy

template <typename T, std::size_t N>
struct my_array
{
    T data[N];
};

template <typename CIT, typename IT>
constexpr void copy(CIT begin, CIT end, IT dest)
{
    for (CIT it = begin; it != end; ++it)
    {
        *dest = *it;
        ++dest;
    }
}
#endif

template <std::size_t N>
constexpr my_array<char, 2 + 8 * N + 1> format_string_struct_impl()
{
    my_array<char, 2 + 8 * N + 1> res{};
    constexpr char init[] = "{}"; // size == 2
    constexpr char extra[] = R"( {}="{}")"; // size == 8
    copy(init, init + 2, res.data);
    for (std::size_t i = 0; i != N; ++i) {
        copy(extra, extra + 8, res.data + 2 + i * 8);
    }
    return res;
}

template <std::size_t N>
constexpr my_array<char, 2 + 8 * N + 1> format_string_struct()
{
    // Ensure the computation is done compile time.
    constexpr auto res = format_string_struct_impl<N>();
    return res;
}

Demo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文