On Wed, 6 May 2026 at 15:49, Tomasz Kaminski <[email protected]> wrote:
>
>
>
> On Wed, May 6, 2026 at 4:16 PM Jonathan Wakely <[email protected]> wrote:
>>
>> Since C++20 the std::tuple move constructor should be constrained (as
>> modified by LWG 2899).
>>
>> We already define the move constructor as defaulted, but it's not
>> implicitly defined as deleted for non-move-constructible element types
>> because the _Tuple_impl(_Tuple_impl&&) constructor is user-provided and
>> unconstrained. For C++20 and later we use a requires-clause to constrain
>> the defaulted tuple(tuple&&) constructor.
>>
>> Ideally we'd make this change pre-C++20 as well, but that's harder to do
>> without using a requires-clause, so this change is only for C++20 and
>> later. I think that's OK, but if we need to change it for pre-C++20
>> later we can consider inheriting from _Enable_copy_move<..., tuple> to
>> make the defaulted move constructor defined as deleted.
>>
>> libstdc++-v3/ChangeLog:
>>
>>         PR libstdc++/78302
>>         PR libstdc++/71301
>>         * include/std/tuple [C++20] (tuple(tuple&&)): Add
>>         requires-clause.
>>         * testsuite/20_util/tuple/cons/78302.cc: New test.
>> ---
>>
>> Tested x86_64-linux.
>>
>>  libstdc++-v3/include/std/tuple                     |  4 +++-
>>  libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc | 11 +++++++++++
>>  2 files changed, 14 insertions(+), 1 deletion(-)
>>  create mode 100644 libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc
>>
>> diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
>> index cbacd5a3c977..64b96fe4f599 100644
>> --- a/libstdc++-v3/include/std/tuple
>> +++ b/libstdc++-v3/include/std/tuple
>> @@ -954,7 +954,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>
>>        constexpr tuple(const tuple&) = default;
>>
>> -      constexpr tuple(tuple&&) = default;
>> +      constexpr
>> +      tuple(tuple&&) requires (is_move_constructible_v<_Elements> && ...)
>
> Could you add test for tuple of references (lvalue and rvalue)? I think the 
> traits
> gives correct result,  but I am not sure.
>>
>> +       = default;
>>
>>        template<typename... _UTypes>
>>         requires (__constructible<const _UTypes&...>())
>> diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc 
>> b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc
>> new file mode 100644
>> index 000000000000..b3c6bd67fd27
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/78302.cc
>> @@ -0,0 +1,11 @@
>> +// { dg-do compile { target c++20 } }
>> +
>> +// Bug 78302 is_move_constructible_v<tuple<nonmovable>> should be false
>> +// LWG 2899. is_(nothrow_)move_constructible and tuple, optional and 
>> unique_ptr
>> +
>> +#include <tuple>
>> +#include <type_traits>
>> +
>> +struct NotMovable { NotMovable(NotMovable&&) = delete; };
>> +static_assert(!std::is_move_constructible_v<std::tuple<NotMovable>>);
>> +static_assert(std::is_nothrow_move_constructible_v<std::tuple<int>>);

Is this good enough?


#include <tuple>
#include <type_traits>

struct NotMovable { NotMovable(NotMovable&&) = delete; };
static_assert(!std::is_move_constructible_v<std::tuple<NotMovable>>);
static_assert(!std::is_move_constructible_v<std::tuple<int, NotMovable>>);
static_assert(!std::is_move_constructible_v<std::tuple<int&, NotMovable>>);
static_assert(!std::is_move_constructible_v<std::tuple<int&&, NotMovable>>);
static_assert(std::is_nothrow_move_constructible_v<std::tuple<int>>);
static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&>>);
static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&&>>);
static_assert(std::is_nothrow_move_constructible_v<std::tuple<int&&, int&>>);

(It passes)

Reply via email to