In short: std::get<T&>('tuple-like')
does not work when using ranges library in MSVC, and I wonder what is expected according to the C++ standard.
I cannot get the code below to compile correctly on MSVC 19.40. It does work with both gcc and clang, though, and I am yet to find information that speaks in favour of MSVC's behaviour.
sample code
#include <tuple>
#include <ranges>
#include <algorithm>
int main() {
using namespace std::views;
char foo{};
std::ranges::for_each(zip(iota(0, 2) | transform([&](int i) -> char& { return foo; })),
[] (auto t) { auto bar = std::get<char&>(t); });
return 0;
}
error message
error C2039: '_Ttype': is not a member of 'std::_Tuple_element<_Ty,std::tuple<>>'
with
[
_Ty=char &
]
Should I expect std::get
to work here, or am I missing something?
The issue seems to be related to using
std::ranges::for_each(..., [] (auto t) { ... });
i.e. with auto
parameter. Simply replacing auto
with std::tuple<char&>
works. I am still unsure whether this behaviour is correct, but it does compile with all three compilers.
To make sure no unwanted tuple conversion was applied (i.e. std::tuple<char> <-> std::tuple<char&>
), I replaced char foo{};
from the question with a no-copy-no-move structure
struct no_copy_move {
no_copy_move() = default;
no_copy_move(no_copy_move const&) = delete;
no_copy_move(no_copy_move&&) = delete;
};
no_copy_move foo{};
and then changed the lambdas
[&](int i) -> char& { return foo; }
[] (auto t) { auto bar = std::get<char&>(t); }
to
[&](int i) -> no_copy_move& { return foo; }
[] (std::tuple<no_copy_move&> t) { auto& bar = std::get<no_copy_move&>(t); }
which also compiles.
TLDR
I do not know if std::get
should work with auto
parameter or not, but changing it to std::tuple<char&>
works.