ericniebler / stl2

LaTeX and Markdown source for the Ranges TS/STL2 and associated proposals
88 stars 8 forks source link

`std::tie` is currently incompatible with foo_result #572

Open cjdb opened 6 years ago

cjdb commented 6 years ago

From cmcstl2's partial_sort_copy:

std::tie(first, r) = ext::copy(std::move(first), last, std::move(r), result_last);

Diagnostic:

cmcstl2/include/stl2/detail/algorithm/partial_sort_copy.hpp: In instantiation of ‘constexpr I2 __stl2::__partial_sort_copy_fn::operator()(I1, S1, I2, S2, Comp, Proj1, Proj2) const [with I1 = int*; S1 = int*; I2 = int*; S2 = int*; Comp = __stl2::less<void>; Proj1 = __stl2::identity; Proj2 = __stl2::identity]’:
cmcstl2/test/algorithm/partial_sort_copy.cpp:119:38:   required from here
cmcstl2/include/stl2/detail/algorithm/partial_sort_copy.hpp:43:25: error: no match for ‘operator=’ (operand types are ‘std::tuple<int*&, int*&>’ and ‘__stl2::copy_result<int*, int*>’)
      std::tie(first, r) =
      ~~~~~~~~~~~~~~~~~~~^
       ext::copy(std::move(first), last, std::move(r), result_last);
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/8/functional:54,
                 from cmcstl2/include/stl2/functional.hpp:16,
                 from cmcstl2/include/stl2/detail/algorithm/partial_sort_copy.hpp:16,
                 from cmcstl2/test/algorithm/partial_sort_copy.cpp:21:
/usr/include/c++/8/tuple:1209:7: note: candidate: ‘std::tuple<_T1, _T2>& std::tuple<_T1, _T2>::operator=(const std::tuple<_T1, _T2>&) [with _T1 = int*&; _T2 = int*&]’
       operator=(const tuple& __in)
       ^~~~~~~~
/usr/include/c++/8/tuple:1209:7: note:   no known conversion for argument 1 from ‘__stl2::copy_result<int*, int*>’ to ‘const std::tuple<int*&, int*&>&’
/usr/include/c++/8/tuple:1216:7: note: candidate: ‘std::tuple<_T1, _T2>& std::tuple<_T1, _T2>::operator=(std::tuple<_T1, _T2>&&) [with _T1 = int*&; _T2 = int*&]’
       operator=(tuple&& __in)
       ^~~~~~~~
/usr/include/c++/8/tuple:1216:7: note:   no known conversion for argument 1 from ‘__stl2::copy_result<int*, int*>’ to ‘std::tuple<int*&, int*&>&&’
/usr/include/c++/8/tuple:1225:9: note: candidate: ‘template<class _U1, class _U2> std::tuple<_T1, _T2>& std::tuple<_T1, _T2>::operator=(const std::tuple<_U1, _U2>&) [with _U1 = _U1; _U2 = _U2; _T1 = int*&; _T2 = int*&]’
         operator=(const tuple<_U1, _U2>& __in)
         ^~~~~~~~
/usr/include/c++/8/tuple:1225:9: note:   template argument deduction/substitution failed:
In file included from cmcstl2/test/algorithm/partial_sort_copy.cpp:21:
cmcstl2/include/stl2/detail/algorithm/partial_sort_copy.hpp:43:25: note:   ‘__stl2::copy_result<int*, int*>’ is not derived from ‘const std::tuple<_T1, _T2>’
      std::tie(first, r) =
      ~~~~~~~~~~~~~~~~~~~^
       ext::copy(std::move(first), last, std::move(r), result_last);
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/8/functional:54,
                 from cmcstl2/include/stl2/functional.hpp:16,
                 from cmcstl2/include/stl2/detail/algorithm/partial_sort_copy.hpp:16,
                 from cmcstl2/test/algorithm/partial_sort_copy.cpp:21:
/usr/include/c++/8/tuple:1233:9: note: candidate: ‘template<class _U1, class _U2> std::tuple<_T1, _T2>& std::tuple<_T1, _T2>::operator=(std::tuple<_U1, _U2>&&) [with _U1 = _U1; _U2 = _U2; _T1 = int*&; _T2 = int*&]’
         operator=(tuple<_U1, _U2>&& __in)
         ^~~~~~~~
/usr/include/c++/8/tuple:1233:9: note:   template argument deduction/substitution failed:
In file included from cmcstl2/test/algorithm/partial_sort_copy.cpp:21:
cmcstl2/include/stl2/detail/algorithm/partial_sort_copy.hpp:43:25: note:   ‘__stl2::copy_result<int*, int*>’ is not derived from ‘std::tuple<_T1, _T2>’
      std::tie(first, r) =
      ~~~~~~~~~~~~~~~~~~~^
       ext::copy(std::move(first), last, std::move(r), result_last);
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/8/functional:54,
                 from cmcstl2/include/stl2/functional.hpp:16,
                 from cmcstl2/include/stl2/detail/algorithm/partial_sort_copy.hpp:16,
                 from cmcstl2/test/algorithm/partial_sort_copy.cpp:21:
/usr/include/c++/8/tuple:1241:9: note: candidate: ‘template<class _U1, class _U2> std::tuple<_T1, _T2>& std::tuple<_T1, _T2>::operator=(const std::pair<_U1, _U2>&) [with _U1 = _U1; _U2 = _U2; _T1 = int*&; _T2 = int*&]’
         operator=(const pair<_U1, _U2>& __in)
         ^~~~~~~~
/usr/include/c++/8/tuple:1241:9: note:   template argument deduction/substitution failed:
In file included from cmcstl2/test/algorithm/partial_sort_copy.cpp:21:
cmcstl2/include/stl2/detail/algorithm/partial_sort_copy.hpp:43:25: note:   ‘__stl2::copy_result<int*, int*>’ is not derived from ‘const std::pair<_T1, _T2>’
      std::tie(first, r) =
      ~~~~~~~~~~~~~~~~~~~^
       ext::copy(std::move(first), last, std::move(r), result_last);
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/8/functional:54,
                 from cmcstl2/include/stl2/functional.hpp:16,
                 from cmcstl2/include/stl2/detail/algorithm/partial_sort_copy.hpp:16,
                 from cmcstl2/test/algorithm/partial_sort_copy.cpp:21:
/usr/include/c++/8/tuple:1250:9: note: candidate: ‘template<class _U1, class _U2> std::tuple<_T1, _T2>& std::tuple<_T1, _T2>::operator=(std::pair<_U1, _U2>&&) [with _U1 = _U1; _U2 = _U2; _T1 = int*&; _T2 = int*&]’
         operator=(pair<_U1, _U2>&& __in)
         ^~~~~~~~
/usr/include/c++/8/tuple:1250:9: note:   template argument deduction/substitution failed:
In file included from cmcstl2/test/algorithm/partial_sort_copy.cpp:21:
cmcstl2/include/stl2/detail/algorithm/partial_sort_copy.hpp:43:25: note:   ‘__stl2::copy_result<int*, int*>’ is not derived from ‘std::pair<_T1, _T2>’
      std::tie(first, r) =
      ~~~~~~~~~~~~~~~~~~~^
       ext::copy(std::move(first), last, std::move(r), result_last);
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A viable solution will possibly need to go through LEWG first, but I am of the opinion that this is a workaround, not the way things should be done:

{
   auto result = ext::copy(std::move(first), last, std::move(r), result_last);
   first = std::move(result.in);
   r = std::move(result.out);
}

Proposal 1

Make copy_result<I, O>, etc. implicitly convertible to tuple<I&, O&> for non-const rvalues only.

I don't expect people to start misusing this particular feature, but I could be naïve.

Proposal 2

Add exposition-only result types that all result types can inherit from, (e.g. struct copy_result : __in_out_result<I, O>), and add a constructor to std::tuple for each exposition-only result type:

template<class X>
requires Same<remove_reference_t<X>, __in_out_result<I, O>> // deliberately not remove_cvref_t
tuple(X&& algorithm_result);

I am not sure of the implications for this one.

Proposal 3

Change std::tie so that it returns an object of an exposition-only type that's common to all result types, std::tuple, and std::pair, and provide constructors for this common type.

Again, I'm not sure of the implications, and it's potentially a lot of extra work involved. Having said that, it does feel like the best of the three solutions I've thought of so far, since we can have other yet-to-be-invented types take advantage of std::tie.

timsong-cpp commented 6 years ago

It's a language issue that we don't have an SB-equivalent for existing things.

I'd say that this is NAD.

cjdb commented 6 years ago

I think this issue inadvertently asks for something that rhymes with __common_tuple, so I might investigate if this is possible, and then mention it in P1035R2 if it is relevant.

That is, assuming @caseycarter doesn't convince me to nuke __common_tuple altogether.

ericniebler commented 6 years ago

I would love for the need for __commom_tuple to die. I would also like the tuple and pair assignment operators to accept any type that is compatible with the structured binding of the appropriate arity.

CaseyCarter commented 6 years ago

This feels more like a feature request than a proper issue to me. LEWG very deliberately chose to break anything tuple-related when they asked for named return types. It's very much by design that "std::tie is currently incompatible with foo_result."

That is, assuming @CaseyCarter doesn't convince me to nuke __common_tuple altogether.

It would be silly to add another generic product type with reference semantics to the standard library. If tuple isn't generic and/or reference-y enough we should fix it. We don't want to duplicate all the support machinery, we really don't want to introduce 8 more overloads of std::get.