使用C ++ 11将可变参数函数参数转换为可变参数函数

时间:2013-12-04 15:56:58

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

我想将调用转发到具有可变方法的库。我能想出的最简单的例子是:

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

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

正如你所看到的,我已经走了。但是,即使这个编译,它似乎导致堆栈有一个摇摆,我看到应用程序退出时出错。从编译器的角度来看,我可以理解这个解决方案存在问题。

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

任何帮助表示赞赏!

1 个答案:

答案 0 :(得分:9)

你采取的方法本身非常理智,安全和健全。例如,下面的程序使用可变参数模板参数并将它们转发到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类型。例如,使用my_printf()致电std::string,您将收到与此类似的警告:

./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 - 这样做很有帮助。

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