【问题标题】:A function with variable number of arguments with known types, the c++11 way具有可变数量的已知类型的参数的函数,c ++ 11方式
【发布时间】:2012-04-20 03:04:58
【问题描述】:

我已经知道 stdarg.h 在 c++ 中使用可变参数的方法,例如 here 中讨论的那样。 我也知道 c++11 标准具有可变参数模板,如 here 所述。

但是在上述两种方案中,我们都不知道(也不能强制)编译时的参数类型 afaik。我正在寻找的是将 known types 的变量参数传递给函数。我认为这是可以做到的,因为我读过它here

可变参数模板,也可用于创建接受可变数量参数的函数,通常是更好的选择,因为它们不会对参数的类型施加限制,不执行整数和浮点提升,并且是类型安全的。

有可能吗?如果是,我该怎么做?

【问题讨论】:

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


    【解决方案1】:

    使用可变参数模板编写函数很简单,它接受任意数量的参数。与一般模式的唯一区别是,具体类型用作第一个参数(头) - 而不是模板参数。以下示例显示了一个函数foobar,它接受任意数量的字符串。

    // used for end of recursion - and for the empty arguments list
    void foobar() { }
    
    template <typename ...Tail>
    void foobar(const std::string& head, Tail&&... tail)
    {
        // do something with head
        std::cout << head << '\n';
        // call foobar recursively with remaining arguments
        foobar(std::forward<Tail>(tail)...);
    }
    
    foobar("Hello", "World", "...");
    

    就个人而言,我更喜欢使用std::initializer_list 而不是可变参数模板。因为可变参数模板更复杂,需要额外的经验。使用std::initializer_list,它可能看起来像这样:

    void foobar(std::initializer_list<std::string> values)
    {
        for (auto& value : values) {
            // do something with value
            std::cout << value << '\n';
        }
    }
    
    foobar({ "Hello", "World", "...", });
    

    不幸的是,将std::initializer_list 与常规函数一起使用时需要额外的花括号。如果使用新的初始值设定项语法,则构造函数不需要它们。

    编辑:根据反馈重写答案。特别是我更改了两个解决方案/示例的顺序。

    【讨论】:

    • 我认为这完全是我的误解。我知道第二种方式,但我一直认为无法控制参数类型。这不是真的。因为该函数采用已知类型的第一个参数(此处为字符串),所以它被隐式强制具有该类型的参数。谢谢。
    • 您可能需要先移动第二个密码框。这是一个非常好的解决问题的方法,而initializer_list 版本则不是。我打算用 SFINAE 之类的东西发布一个大而复杂的东西,但这要合理得多。
    • @nosid 如果您混合使用 std::initializer_list 和可变参数模板方法,您实际上可以避免使用花括号,方法是在 std::initializer_list 版本周围创建可变参数模板包装器,如下所示:@ 987654321@.
    • @FabioA。你可以这样做,但是你失去了std::initializer_list 的一个重要好处。不再可能对元素使用 大括号初始化,即以下内容适用于 std::initializer_listfoobar({{"foo", 1, 2}, {"bar", 2, 1}});
    • @nosid 确实,即使包装器可用,它仍然可以工作。要将这些字符串构造函数与模板包装器一起使用,您必须明确命名 std::string 类型。它在this other coliru 中进行了说明。
    【解决方案2】:

    如果变量参数都是一种类型,您可以更改函数签名以获取这些类型的数组,而不是使用“...”。

    【讨论】:

    • 一种类型的数组需要迭代,而使用可变参数函数提供了编译时内联机制。你可能会说在数组上循环并不是那么耗时,而是在另一个多个大循环中考虑它。
    猜你喜欢
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 2021-04-29
    相关资源
    最近更新 更多