如何在变量参数长度C++宏(...和va_args)?

发布于 2025-01-21 01:21:34 字数 537 浏览 0 评论 0原文

我正在尝试编写一个 C++ 宏,它将取代经常需要的冗长代码,例如

switch (id) {
case 0:
    s << myFloat;
    break;
case 1:
    s << myInt;
    break;
default: break;
}

使用 DESERIALIZE_MEMBERS(myFloat, myInt) 之类的代码。 sid 不会更改用例的名称,因此它们不需要是宏参数。

它应该支持可变参数长度,因此对于另一种情况,DESERIALIZE_MEMBERS(myString, myArrayOfInts, myLong) 也应该可以工作,向 switch 表达式添加第三个 case 语句。

但是,我不清楚如何在宏内为每个参数迭代 case N: 中的 N 值。

在标准 C++ 宏中这可能吗?

I am trying to write a C++ macro which would substitue a frequently-needed verbose code like

switch (id) {
case 0:
    s << myFloat;
    break;
case 1:
    s << myInt;
    break;
default: break;
}

with something like DESERIALIZE_MEMBERS(myFloat, myInt). s and id will not change names for the use case, so they don't need to be macro parameters.

It should support variable argument length, so DESERIALIZE_MEMBERS(myString, myArrayOfInts, myLong) for another case should also work, adding a third case statement to the switch expression.

However, it's not clear to me how to iterate the N value in case N: inside the macro for each argument.

Is that possible at all in standard C++ macros?

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

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

发布评论

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

评论(1

你的心境我的脸 2025-01-28 01:21:34

,这是一个解决方案。

首先是编译时常量类型和值:

template<auto X>
using constant_t = std::integral_constant<decltype(X), X>;
template<auto X>
constexpr constant_t<X> constant_v;

接下来是此类常量的变体:

template<auto...Is>
using enum_t = std::variant<constant_t<Is>...>;

这使您可以在运行时生成编译时枚举值并使用它。

现在有一些代码可以让您将运行时整数转换为编译时枚举值:

template<std::size_t...Is>
constexpr enum_t<Is...> get_enum_v( std::index_sequence<Is...>, std::size_t i ) {
  using generator = enum_t<Is...>(*)();
  constexpr generator generators[] = {
    +[]()->enum_t<Is...> {
      return constant_v<Is>;
    }...
  };
  return generators[i]();
}
template<std::size_t N>
auto get_enum_v( std::size_t i ) {
  return get_enum_v( std::make_index_sequence<N>{}, i );
}

因此,如果您执行 get_enum_v<10>(2),它会返回一个 enum_t<...> 有 10 个替代项,其中包含索引 2 的替代项,该替代项是 constant_v

现在我们只得到一个元组和一个索引,然后我们在索引描述的元组元素上调用一个函数:

template<class F, class Tuple>
auto apply_to_nth_element( std::size_t i, F f, Tuple tuple ) {
  constexpr std::size_t N = std::tuple_size<Tuple>{};
  auto Index = get_enum_v<N>( i );
  return std::visit( [&](auto I){
    return f( std::get<I>(tuple) );
  }, Index );
}

您现在可以这样做:

apply_to_nth_element(id, [&](auto& elem) {
  s << elem;
}, std::tie(myFloat, myInt));

而不是

DESERIALIZE_MEMBERS(myFloat, myInt)

实例;可以在早于 但很快就会变得非常丑陋。

In , here is a solution.

First a compile-time constant type and value:

template<auto X>
using constant_t = std::integral_constant<decltype(X), X>;
template<auto X>
constexpr constant_t<X> constant_v;

Next, a variant over such constants:

template<auto...Is>
using enum_t = std::variant<constant_t<Is>...>;

this lets you generate a compile-time enumeration value at runtime and use it.

Now some code that lets you convert a runtime integer into a compile-time enumeration value:

template<std::size_t...Is>
constexpr enum_t<Is...> get_enum_v( std::index_sequence<Is...>, std::size_t i ) {
  using generator = enum_t<Is...>(*)();
  constexpr generator generators[] = {
    +[]()->enum_t<Is...> {
      return constant_v<Is>;
    }...
  };
  return generators[i]();
}
template<std::size_t N>
auto get_enum_v( std::size_t i ) {
  return get_enum_v( std::make_index_sequence<N>{}, i );
}

so if you do get_enum_v<10>(2), it returns an enum_t<...> with 10 alternatives containing the alternative with index 2, which is a constant_v<std::size_t, 2>.

Now we just get a tuple and an index, and we call a function on the tuple element described by the index:

template<class F, class Tuple>
auto apply_to_nth_element( std::size_t i, F f, Tuple tuple ) {
  constexpr std::size_t N = std::tuple_size<Tuple>{};
  auto Index = get_enum_v<N>( i );
  return std::visit( [&](auto I){
    return f( std::get<I>(tuple) );
  }, Index );
}

you can now do this:

apply_to_nth_element(id, [&](auto& elem) {
  s << elem;
}, std::tie(myFloat, myInt));

instead of

DESERIALIZE_MEMBERS(myFloat, myInt)

Live example; Code can be rewritten in versions older than but gets extremely ugly very fast.

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