Inconsistent behavior of std::common_reference_with on tuples. Which is correct?
Asked Answered
M

1

17

Background:

I'm trying to port a library to compile on MSVC. That library stores data in a tuple of vectors (std::tuple<std::vector<Ts>...>), and uses a custom iterator to iterate over all vectors simultaneously (similar to what a zip_iterator does).

The iterator defines types that look like this (assuming Ts... -> <int, int>) :

`value_type` is `std::tuple<int, int>`  
`reference`  is `std::tuple<int&, int&>`

The problem is that on latest MSVC (v. 19.35), this iterator does not satisfy the concept of std::input_iterator, while it does satisfy it on gcc/clang.

On further investigation, i found the failure to be due to inconsistent behaviour of the std::common_reference concept on tuples.

Issue:

The following static_assert fails on MSVC, while it doesn't fail on gcc/clang

using T = std::tuple<int, int>&;
using U = std::tuple<int&, int&>;
static_assert(std::common_reference_with<T, U>, "failed common_reference_with");

Here it is on Godbolt (with an iterator example as well)

Question:

Is a type like std::tuple<int, int>& supposed to have a "common_reference_with" std::tuple<int&, int&> ? MSVC says no, gcc says yes.
Which of the two behaviours should be expected according to the standard in C++20 and forward?

Is there any easy way to make this iterator succeed the iterator concept checks on MSVC (ie, force the two types to have a common reference)?

I also found some great answers by Eric Niebler, on std::common_reference (SO) and on proxy iterators (on his blog).

However, it's not clear to me what is supposed to happen in C++20 and later.

Maples answered 17/8, 2023 at 13:24 Comment(0)
F
16

Is a type like std::tuple<int, int>& supposed to have a "common_reference_with" std::tuple<int&, int&> ?

Yes, P2321 guarantees that they have common reference type tuple<int&, int&> and model common_reference_with.

Since such enhancement of common_reference for tuple is a C++23 feature, you need to change the MSVC compiler option to /std:c++latest to make it work.

It is worth noting that P2165 makes tuple compatible with other tuple-like objects such as array, pair and ranges::subrange, so it also has a valid common_reference type with the other three.

Fiver answered 17/8, 2023 at 13:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.