Is gcc wrong by allowing the code with compound statement to compile?

Viewed 97

I'm trying to add tuple elements into a vector. The below code is working:

#include <iostream>
#include <vector>
#include <tuple>
#include <string>
#include <utility>

template<class ... T>
std::vector<void *> to_vector(std::tuple<T...> x) {
    std::vector<void*> out;
    out.reserve(sizeof...(T));
    std::apply([&out](auto&&... args) {
        (out.push_back(new std::remove_reference_t<decltype(args)>(std::forward<decltype(args)>(args))), ...);
    }, x);
    return out;
}

int main() {
    std::tuple<int, double, std::string, int> x = {1, 3.14, "test", 9};
    std::vector<void *> v = to_vector(x);
    int i = 0;
    std::apply([&](auto&&... args) {
        ((std::cout << *(std::remove_reference_t<decltype(args)>*)v[i++] << std::endl), ...);
    }, x);
    // ...
}

But in order to make the code a little bit more readable, I tried to do the following inside the lambda expression in std::apply:

std::apply([&out](auto&&... args) {
    (({
        using elem_type = std::remove_reference_t<decltype(args)>;
        out.push_back(new elem_type(std::forward<elem_type>(args)));
    }), ...);
}, x);

The above code compiles on gcc 9.2, but does not compile on clang 9.0.0. Then, I tried to discover why: according to cppreference, fold expressions pack item is expected to be an expression statement, in the above code, I'm passing a compound statement, not a expression statement. If I make this compound statement become a lambda expression, I can make it work on clang:

std::apply([&out](auto&&... args) {
    ([&](){
        using elem_type = std::remove_reference_t<decltype(args)>;
        out.push_back(new elem_type(std::forward<elem_type>(args)));
    }(), ...);
}, x);

With that in mind, can I say that in the first edit approach that gcc is wrong to allow the code to compile?

0 Answers
Related