1

我发现了一篇有趣的文章,并用 MSVS 2017 尝试了它的代码:

#include <utility>
#include <tuple>

template <typename... Args, typename Func, std::size_t... Idx>
void for_each(const std::tuple<Args...>& t, Func&& f, std::index_sequence<Idx...>) {
    f(std::get<Idx>(t))...;
}

template <typename... Args, typename Func>
void for_each(const std::tuple<Args...>& t, Func&& f) {
    for_each(t, f, std::index_sequence_for<Args...>{});
}

template <typename T>
void Write(std::wostream & out, const T & t)
{
    out << t;
}

template<typename ...Args>
void WriteV(std::wostream & out, Args&... args)
{
    for_each(std::tuple<Args&...>(args...), [&out](auto& a) { Write(out, a); });
}

struct A
{
    int n;
    std::wstring s;
    double d;
};

    void main()
    {
        std::wostringstream out;

        A a{ 1, std::wstring(L"2"), 3.0 };
        WriteV(a.n, a.s, a.d);
    }

,但代码没有编译错误:

error C2760: syntax error: unexpected token '...', expected ';'
error C3520: 'Idx': parameter pack must be expanded in this context

这是否意味着VS2017不完全支持折叠表达式?

4

2 回答 2

6

这段代码只需要几个语法修复:

(f(std::get<Idx>(t)), ...);

WriteV(out, a.n, a.s, a.d);

请注意,由于某种原因,此代码不需要很长。它可以替换为

 template<typename ... Args>
 void WriteV(std::wostream & out, Args const & ... args)
 {
     (out << ... << args);
 }
于 2019-01-21T12:59:41.607 回答
4

这种方式是错误的

f(std::get<Idx>(t))...;

你必须选择。

(1) 你想f()用所有参数只调用一次吗?在这种情况下,您必须将省略号 (" ...")放在调用中

f(std::get<Idx>(t)...);

(2)还是您想要(在您的示例中是这种情况)调用f()每个参数(N参数,N调用)?在这种情况下,您可以(从 C++17 开始)使用带有逗号运算符的模板折叠添加几个括号

    (f(std::get<Idx>(t) , ...);
// .^...................^....^   <- comma and parentheses

第二种方式,在 C++17 之前,可以在(通常未使用的)数组的初始化中进行模拟。如下

using unused = int[];

(void) unused { 0, ((void)f(std::get<Idx>(t)), 0)... };
于 2019-01-21T13:07:16.753 回答