【问题标题】:Forward variadic function arguments to variadic function using C++11使用 C++11 将可变参数函数参数转发到可变参数函数
【发布时间】:2013-12-04 15:56:57
【问题描述】:

我想将调用转发到具有可变参数方法的库。我能想出的最简单的例子来复制这个问题是这样的:

void Bar(int useless, ...)
{
  //Does something
}

template<typename... Args>
void Foo(int useless, Args... args)
{
  Bar(useless, args...);
}

如您所见,我已经尝试过了。但是,即使编译成功,它似乎也会导致堆栈出现摆动,并且我在应用程序退出时看到错误。我可以从编译器的角度理解这个解决方案是有问题的。

我不确定如何让这个工作,或者是否有可能让这个工作。我看到有些人建议在类似情况下使用“指数技巧”,但我无法在这种特殊情况下使用它。

任何帮助表示赞赏!

【问题讨论】:

  • 变量参数的 C 版本非常有限,可能是来自 Foo 的 args 被传递给 bar 并以不正确的类型检索的情况。见stackoverflow.com/questions/15026671/c-variable-argument-list
  • 你能提供一个产生错误的完整样本吗? msvc、clang 和 gcc 编译的版本对我来说似乎运行良好。
  • 这适用于可简单复制的类型(假设Bar 有一些方法可以确定它们的类型);其他类型根本无法通过 ... 传递,您无法解决此问题。

标签: c++ templates c++11 variadic


【解决方案1】:

您所采取的方法本身就非常理智、安全和可靠。例如,下面的程序使用可变模板参数并将它们转发给std::printf(),这是一个接受可变数量参数的 C 风格函数:

#include <utility>
#include <cstdio>

template <unsigned int S, typename ...T>
void my_printf(const char (&fmt)[S], T&&... args) {
    std::printf(fmt, std::forward<T>(args)...);
}

int main(int argc, const char* argv[]) {
    my_printf("Hello, %s!\n", "World!");
    my_printf("I will count to %u...\n", 10);
    for (int i = 0; i < 10; ++i)
        my_printf("%s %s %u\n", "...", "and", i + 1);
    my_printf("And here are my arguments :)\n");
    for (int i = 0; i < argc; ++i)
        my_printf("argv[%u] == %s\n", i, argv[i]);
}

未定义行为的问题和可能的堆栈损坏是由其他原因引起的。在 C++ 中,这很可能是由于通过 C 的变量参数列表传递非 POD 类型(即,将 std::string 传递给 printf() 可以做到这一点)。

不幸的是,像 "format attribute" 这样的编译器扩展在这里没有帮助。但是编译器可能会警告您有关非 POD 类型的信息。例如,使用std::string 调用my_printf(),您将获得类似以下的警告:

./test.cc:7:46: error: cannot pass objects of non-trivially-copyable type ‘class std::basic_string<char>’ through ‘...’
     std::printf(fmt, std::forward<T>(args)...);

                                          ^

当然,编译器可能无法为您捕捉到其他内容。不幸的是,没有比调试程序并查看究竟是什么导致它崩溃更好的方法了。

由于您正在进入 C 和不安全参数传递的黑暗水域,调试器在这里是您的朋友,我还建议您使用 Valgrind - 它非常有助于捕捉这样的东西。

希望对您有所帮助。祝你好运!

【讨论】:

    猜你喜欢
    • 2011-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 2012-11-27
    • 1970-01-01
    相关资源
    最近更新 更多