3

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?

João Paulo
  • 6,300
  • 4
  • 51
  • 80
  • 4
    Given that `({ ... })` itself is a gcc extension, this seems to be neither right, nor wrong. – Sam Varshavchik Mar 04 '20 at 02:43
  • Do you have a link for this? – João Paulo Mar 04 '20 at 02:47
  • 2
    A link for what? The fact that `({ ... })` is a gcc extension? It's documented here https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html under the heading of "C extension". – Sam Varshavchik Mar 04 '20 at 02:53
  • Thanks! A link just to know what's it. I didn't know about it. – João Paulo Mar 04 '20 at 02:54
  • 1
    Well, I would say the fact that no other C or C++ compiler accepts such a syntax, nor would you find it in any C++ book (except, perhaps, mentioned as a gcc extension) might be a good indication... – Sam Varshavchik Mar 04 '20 at 02:58
  • 1
    @SamVarshavchik Really? _No_ other C++ compiler? https://godbolt.org/z/W3Xqee – Barry Mar 04 '20 at 03:02
  • Well, this was a gcc-only extension originally. It's entirely possible that other compilers have picked it up. I don't really have any documentation that shows which one was first, but since this is not standard C or C++ syntax, there is no requirement for a particular compiler to implement any particular semantics for this construct. So it's entirely possible that the supporting compilers might differ in what they do in these kinds of corner cases. Yay for standards! – Sam Varshavchik Mar 04 '20 at 03:06
  • Is gcc wrong to support a feature that is documented as a gcc extension? Nope. Is any compiler wrong to support a non-standard extension? No, as long as they document it as being a non-standard extension, Yes if their documentation claims it as being part of Standard C++ (some vendors are known for documenting their non-standard extensions as standard). Is a programmer wrong to use such features? No, as long as they accept and manage the consequences (e.g. code may not compile at all, or if it does compile, it may work differently with a different compiler or compiler version). – Peter Mar 04 '20 at 03:49
  • And there is flag (`-pedantic`) to disable extension. – Jarod42 Mar 04 '20 at 08:52
  • 1
    @Peter -- formally, in the absence of undefined behavior, when the compiler encounters code that is invalid under the standard it must issue a diagnostic. Having done that, it is free to continue to compile the code, with an implementation-specific meaning (i.e., an extension). – Pete Becker Mar 04 '20 at 14:58
  • @PeteBecker: True, but only if the compiler claims to be conformant—GCC is free to say that its conforming implementation is (only) that invoked by `g++ -pedantic`. – Davis Herring Mar 04 '20 at 20:04

0 Answers0