1

I found an interesting article and tried its code with 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);
    }

, but the code did not compile with errors:

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

does it mean that VS2017 does not fully support fold expressions?

max66
  • 65,235
  • 10
  • 71
  • 111
Alexey Starinsky
  • 3,699
  • 3
  • 21
  • 57

2 Answers2

6

This code needs just a couple of syntax fixes:

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

and

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

Note that this code is unnecessary long for some reason. It can be replaced with just

 template<typename ... Args>
 void WriteV(std::wostream & out, Args const & ... args)
 {
     (out << ... << args);
 }
user7860670
  • 35,849
  • 4
  • 58
  • 84
4

This way is wrong

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

You have to choose.

(1) do you want to call f() only one time with all arguments? In this case you have to put the ellipsis ("...") inside the call

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

(2) or do you want (I suppose is the case, in your example) call f() with every argument (N argument, N calls)? In this case you can (starting from C++17) use template folding with comma operator adding a couple of parentheses

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

The second way, pre C++17, can be simulated inside the inizialization of an (usually unused) array. Something as follows

using unused = int[];

(void) unused { 0, ((void)f(std::get<Idx>(t)), 0)... };
max66
  • 65,235
  • 10
  • 71
  • 111