【问题标题】:Zero cost abstraction for executing same statement on multiple objects在多个对象上执行相同语句的零成本抽象
【发布时间】:2020-02-29 07:57:34
【问题描述】:

假设三个对象A aB bC c。这三个都有一个签名为void foo(Bar& bar)的方法。

有时我需要编写如下代码:

a.foo(bar);
b.foo(bar);
c.foo(bar);

现在有很多代码重复,尤其是当表达式变长时。

到目前为止,我想出了

foreach (const auto& value : { a, b, c}) value.foo(bar);

但这只有在abc 属于同一类型且fooconst 时才有效。

是否有一种优雅的零成本抽象来一次性抽象出针对不同类型和非常量函数的免费相同方法调用?

这最好适用于涉及value 的任意语句。

【问题讨论】:

  • ABC 是否有共同的基类?如果没有,为什么不呢?
  • @JohnKugelmansupportsMonica 据我了解,使用继承需要指向对象的指针和虚拟方法表查找。这会比直接写出 3 行效率低。

标签: c++ abstraction code-duplication


【解决方案1】:

您可以在parameter pack 的帮助下将它们包装成一个函数模板。

template <typename... T>
void call_bar(Bar& bar, const T&... t) {
    (t.foo(bar), ...);
}

然后

call_bar(bar, a, b, c);

LIVE

【讨论】:

  • 有没有办法对任何一组值进行抽象?例如通过传递适用于每个 T... 的模板化函数
  • @Dracam 您可以传递函数模板的特化,或者您可以包装成函子类并传递它,具体取决于上下文。
  • 我找不到为多个不同的Ts 编写此代码的方法。我什至不认为类型系统允许这样做。所以我正在尝试使用宏,但无法让东西正常工作。
  • @Dracam 你的意思是template &lt;typename F, typename... T&gt; void apply(F&amp;&amp; f, T&amp;&amp;... t) { (f(t), ...); }apply([&amp;](auto &amp; t){ t.foo(bar); }, a, b, c) 一样使用吗?
【解决方案2】:

我自己用聪明的宏解决了最多 5 个参数:

// Does not work on MSVC, since they use a different preprocessor algorithm than clang and gcc.
// Use like this:
//   foreach(const &, myFoo1, myFoo2, myFoo3, _.foo());
//   foreach(&&, a, b, c, sum += _);

#define _GET_FOR_EACH_MACRO(_0, _1, _2, _3, _4, _5, _6, NAME, ...) \
    NAME

#define _FOR_EACH1(refMod, _1, expr) \
    { auto refMod _ = _1; (expr); };

#define _FOR_EACH2(refMod, _1, _2, expr) \
    { auto refMod _ = _1; (expr); }; \
    _FOR_EACH1(refMod, _2, expr)

#define _FOR_EACH3(refMod, _1, _2, _3, expr) \
    { auto refMod _ = _1; (expr); }; \
    _FOR_EACH2(refMod, _2, _3, expr)

#define _FOR_EACH4(refMod, _1, _2, _3, _4, expr) \
    { auto refMod _ = _1; (expr); }; \
    _FOR_EACH3(refMod, _2, _3, _4, expr)

#define _FOR_EACH5(refMod, _1, _2, _3, _4, _5, expr) \
    { auto refMod _ = _1; (expr); }; \
    _FOR_EACH4(refMod, _2, _3, _4, _5, expr)

#define foreach(...) _GET_FOR_EACH_MACRO(__VA_ARGS__, _FOR_EACH5, _FOR_EACH4, _FOR_EACH3, _FOR_EACH2, _FOR_EACH1)(__VA_ARGS__)

由于某种原因,这不适用于 MSVC 2019,因为 __VAR_ARG__ 作为单个参数传递给其他宏,而不是作为多个参数。不过它在 Clang 和 GCC 上运行良好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多