wasthishelpful wasthishelpful - 2 months ago 31
C++ Question

Parameter pack expansion in a lambda with Visual Studio 2015: error C3546

Following this question, I tried to compile the following code:

template<typename... Types>
auto for_each(type_list<Types...>) {
return [](auto&& f) {
using swallow = int[];
(void) swallow { 0, (void(f(tag<Types>{})), 0)... };
};
}


This works fine with gcc, but generate the following error with visual studio 2015:


main.cpp(19): error C3546: '...': there are no parameter packs available to expand

main.cpp(48): note: see reference to function template instantiation 'auto for_each::<lambda_9a452bac795593df4639d6433fa242d3>::operator ()<main::<lambda_b7b233027d9428cb5ddc16c87ea59d21>>(main::<lambda_b7b233027d9428cb5ddc16c87ea59d21> &&) const' being compiled

main.cpp(18): error C3520: 'Types': parameter pack must be expanded in this context

main.cpp(18): error C2672: 'operator __surrogate_func': no matching overloaded function found

main.cpp(18): error C2893: Failed to specialize function template 'auto main::<lambda_b7b233027d9428cb5ddc16c87ea59d21>::operator ()(_T1) const'

main.cpp(18): note: With the following template arguments:

main.cpp(18): note: '_T1=tag<Types>'



Looks like visual compiler fails expansion when symbol
...
is not tied to the parameter pack(?)

Is there a way to solve the problem?

Here is a minimal example to generate the error:

#include <iostream>
#include <string>

template<typename... > struct type_list {};

template<typename T>
struct tag { using type = T; };

template<typename... Types>
auto for_each(type_list<Types...>) {
return [](auto&& f) {
using swallow = int[];
(void) swallow { 0, (void(f(tag<Types>{})), 0)... };
};
}

struct A {
static std::string get_type_name() { return { "A" }; }
};

struct AA : A {
static std::string get_type_name() { return { "AA" }; }
};

int main() {
for_each(type_list<A, AA>{}) (
[&](auto t) {
using B = typename decltype(t)::type;
std::cout << B::get_type_name() << std::endl;
}
);

return 0;
}

Answer

I ended up replacing the for_each function with a structure:

template<typename T> struct for_each {};

template<typename... Types>
struct for_each<type_list<Types...>> {
    template<typename F>
    for_each(F f) {
        using swallow = int[];
        (void) swallow { 0, (f(tag<Types>{}), 0)... };
    }
};

With the slightly modified usage:

int main() {
    for_each<type_list<A, AA>>{
        [&](auto t) {
            using B = typename decltype(t)::type;
            std::cout << B::get_type_name() << std::endl;
        }
    };

    return 0;
}