【问题标题】:Callback a function with previously unknown arguments in C and C++在 C 和 C++ 中回调具有以前未知参数的函数
【发布时间】:2012-02-03 19:22:14
【问题描述】:

我正在考虑做一个take_timing 函数,它会占用传递给它的任何函数的时间。 任何函数意味着调用者不知道这个回调的参数。它也需要回调的参数。但由于它不知道如何调用它,它需要另一个回调函数,即回调的调用者,由函数用户编写。存根是这样的:

void take_timing(
    void (*callback)(),
    void (*caller(void (*callback)(),void* args_struct),
    void* args_struct
)
{
    // Start timer

    caller(callback,args_struct);

    // Stop timer, read timings, record...
}

void some_caller(void (*callback)(),void* args_struct)
{
    // Cast "callback" to function signature
    // Cast args_struct to some struct with args
    // Call the callback with correct args signature
}

我的问题来了:

  1. 有可能吗?
  2. 它可以使用可变参数列表来简化吗?如何?我对此束手无策……
  3. 有更好的方法吗?还是为每个特定案例提供take_timing 更好?
  4. 是否有用于 C++ 的 OOP 设计模式?

我自己放弃了这个,但出于好奇把它放在这里,也许是一些非常有用的见解。

【问题讨论】:

  • 额外抽象的价值是什么?为什么不直接使用带有上下文指针的已知回调函数类型呢?我猜我看不到这里的增值。

标签: c++ c design-patterns callback argument-passing


【解决方案1】:

只需将仿函数作为模板参数。比如:

template<typename F>
nanoseconds take_timing(F f) {

    auto start = high_resolution_clock::now();
    f();
    auto end = high_resolution_clock::now();
    return end - start;
}

long long factorial(int i);

take_timing( [](){factorial(20);} ); // wrap call to function taking arguments in zero-argument lambda

【讨论】:

  • 嗯,这真的很棒,工作完美,不会令人难以置信,非常易于阅读、理解和使用。让我们拭目以待,看看是否也有一种纯 C 的方式。
【解决方案2】:

您正在寻找varargs 支持,它确实存在于 ANSI C 中。如果您搜索它,将会产生大量的谷歌点击。这是随机的:http://www.eskimo.com/~scs/cclass/int/sx11b.html

【讨论】:

  • 好的,但是有没有办法将varargs 传递给另一个函数?在我们的例子中,take_timing 得到一个va_list。但它如何调用caller 并将va_list 的参数传递给它呢?
  • 如果被调用的函数也可以接受参数的 va_list,那么可以。 IE,如果父函数是 foo(va_list args) 那么它当然可以很容易地调用 bar(va_list args),传递相同的参数集(或先处理它)。
  • 我认为它使它成为一个有效的解决方案,尽管令人难以置信。事实上,这就是我第一次想到的,但我不确定传递宏处理的va_list 是否有效。另外,当开始编码时,我发现它的可用性设计并不好,至少对我来说不是。
  • 这绝对是 C++ 解决方案看起来比 C 解决方案更干净的情况之一。您可能需要根据...进行选择...
  • 您不能像在所有情况下那样简单地传递varargs。 C99 定义va_copy。 C89 没有,但如果它不存在可以重新定义:#define va_copy(dest,src) memcpy(&amp;dest, &amp;src, sizeof (va_list))
【解决方案3】:

处理这种情况的一种方法是将 boost::bind 函数对象作为参数: http://www.boost.org/doc/libs/1_48_0/libs/bind/bind.html

您可以隐藏闭包与宏有关的事实。

【讨论】:

  • 也很高兴知道这一点。但我认为它现在可能会被 C++11 标准“弃用”。
猜你喜欢
  • 1970-01-01
  • 2018-06-13
  • 1970-01-01
  • 1970-01-01
  • 2014-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-19
相关资源
最近更新 更多