【问题标题】:Apply function to all elements of parameter pack from a variadic function [duplicate]从可变参数函数将函数应用于参数包的所有元素[重复]
【发布时间】:2018-11-13 12:33:19
【问题描述】:

考虑以下(不工作!)示例:

#include <iostream>

template <typename type> void print(const type & item)
{
    std :: cout << item << std :: endl;
}

template <typename... types> void printall(const types & ... items)
{
    print(items)...;
}

int main()
{
    printall(1, 2, "hello");
}

这里我有一个函数print,它只是打印出它的参数,还有一个可变参数函数printall,它接受一组参数。现在,我想做的只是让printallprint 应用于包items 的每个元素。我怎样才能做到这一点?

注意:我不是询问如何打印一组值。我知道折叠表达式的存在,我知道我可以使用它们将整个 items 扔到 std::cout 中。这里print只是一个例子,可以是任何函数。

我怎样才能做到这一点?这听起来应该非常简单,但我找不到任何(合理的)语法来做到这一点。

【问题讨论】:

  • 我不明白为什么折叠表达式不是答案。 print(items)...; 不编译?
  • 不,print(items)...; 无法编译,我收到以下错误:error: expected ';' after expression
  • 如果您的代码无法编译,请在问题中包含您收到的错误消息。顺便说一句,我认为您正在寻找 std::invokestd::apply(它们完全不同,但我总是混淆它们)
  • (print(items),...); 需要括号和逗号。
  • 好的。哇。这样可行。但这是什么语法……?

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


【解决方案1】:

我想做的只是让printall 申请print 包装物品的每个元素。我怎样才能做到这一点?

选项 - 1

作为 cmets 中建议的用户 @liliscent 和用户 @max66, 在 C++11/C++14 中,您可以使用以下 hacky-way,其行为类似于 C++17 中的 折叠表达式

SEE HERE

#include <iostream>

template <typename type> void print(const type& item)
{
    std::cout << item << '\n';
}

template <typename... types> 
void printall (const types&... items)
{
    using dummy = int[];
    (void)dummy { 0, (print(items), 0)... };
}

选项 - 2

如果上面看起来不够好,请在printall()print() 函数之间提供一个经典的可变参数模板重载作为包装器/帮助器,这样每个模板函数参数都可以在print() 中访问。

SEE HERE

#include <iostream>

template <typename Type> void print(const Type& item)
{
    std::cout << item << '\n';  // print each argument
}

namespace helper 
{
    void printall() {}          // nontemplate overload for last call(i.e, no arguments call)

    template<typename FirstArg, typename... Types>
    void printall(const FirstArg& firstItem, Types&&... items)  
    {
        ::print(firstItem);                             // call print() for each argument
        helper::printall(std::forward<Types>(items)...);// calls the same wrapper::printalll()
    }
}

template <typename... Types> void printall(const Types& ... items)
{
    helper::printall(items...); // calls the wrapper::printall()
}

选项 - 3

但是,如果您可以访问 C++17,只需使用 fold expressions。这提供了一个干净(非hacky)和更少的代码。

SEE HERE

template <typename type> void print(const type& item)
{
    std::cout << item << '\n';
}

template <typename... types> void printall(const types&... items)
{
    (print(items),...);
}

【讨论】:

  • 在 C++11 中,简洁的方式是 using dummy = int[]; (void) dummy{(print(items), 0)...};
  • 在 C++17 中,您可以简单地编写 template &lt;typename ... types&gt; void printall (types const &amp; ... items) { (std::cout &lt;&lt; item &lt;&lt; std::endl, ...); }(也可以使用 '\n' 而不是 std::endl,以避免不必要的刷新)
  • @max66 是的,这正是 OP 不想拥有的。他在 cmets 中以 Note 的形式提到了它。 :) 但可以肯定的是'\n',您将在我的第一个答案中看到。我也会补充第二个。 ;)
  • 对不起...没见过;无论如何,在 C++11/C++14 中(如 liliscent 所建议),您可以尝试 template &lt;typename ... types&gt; void printall (types const &amp; ... items) { using dummy = int[]; (void)dummy { 0, (print(items), 0)... }; );
  • 它是 C++17 模板折叠的常见 C++11/C++14 替代方案(在 C++14 编写 constexpr 模板函数时非常有用)。
猜你喜欢
  • 2011-12-24
  • 1970-01-01
  • 2022-01-20
  • 2022-07-08
  • 1970-01-01
  • 1970-01-01
  • 2017-07-05
  • 2011-04-01
  • 2015-09-26
相关资源
最近更新 更多