On Fri, 24 Oct 2025 at 10:54, Tomasz Kamiński <[email protected]> wrote:
>
> This patch fixes a missing forwarding-reference (&&) in _Bind_fn_t::operator()
> and lambda returned from not_fn<f>.
>
> The bind_front<f>/bind_back<f> tests were updated to use a structure similar
> to r16-3398-g250dd5b5604fbc to cover cases involving zero, one, and many bound
> arguments.
>
>         PR libstdc++/122022
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/functional (_Bind_fn_t): Use forwarding reference as
>         paremeter.
>         (std::not_fn<f>): Use forwarding reference as lambda parameter.
>         * testsuite/20_util/function_objects/bind_back/nttp.cc: Rework tests.
>         * testsuite/20_util/function_objects/bind_front/nttp.cc: Likewise.
>         * testsuite/20_util/function_objects/not_fn/nttp.cc: Add test for
>         argument forwarding.
> ---
> v2 mentions the PR122022 and extend fix to not_fn.

OK, thanks

>
>  libstdc++-v3/include/std/functional           |   8 +-
>  .../function_objects/bind_back/nttp.cc        | 244 +++++++++++------
>  .../function_objects/bind_front/nttp.cc       | 248 +++++++++++-------
>  .../20_util/function_objects/not_fn/nttp.cc   |  47 ++++
>  4 files changed, 366 insertions(+), 181 deletions(-)
>
> diff --git a/libstdc++-v3/include/std/functional 
> b/libstdc++-v3/include/std/functional
> index 8ad73b343bd..dd1aa204eae 100644
> --- a/libstdc++-v3/include/std/functional
> +++ b/libstdc++-v3/include/std/functional
> @@ -928,10 +928,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      {
>        using _Fn = const decltype(__fn)&;
>        template <typename... _Args>
> +       requires is_invocable_v<_Fn, _Args...>
>         constexpr static decltype(auto)
> -       operator()(_Args... __args)
> -         noexcept(is_nothrow_invocable_v<_Fn, _Args...>)
> -         requires is_invocable_v<_Fn, _Args...>
> +       operator()(_Args&&... __args)
> +       noexcept(is_nothrow_invocable_v<_Fn, _Args...>)
>         { return std::invoke(__fn, std::forward<_Args>(__args)...); }
>      };
>  #endif
> @@ -1188,7 +1188,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        using _Fn = decltype(__fn);
>        if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
>         static_assert(__fn != nullptr);
> -      return []<typename... _Args>(_Args... __args) static
> +      return []<typename... _Args>(_Args&&... __args) static
>           noexcept(noexcept(
>             !std::invoke(__fn, std::forward<_Args>(__args)...) ))
>           -> decltype(auto)
> diff --git 
> a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc 
> b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc
> index 4dff909a387..3bea8eced43 100644
> --- a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc
> +++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc
> @@ -39,101 +39,145 @@ test01()
>        >);
>  }
>
> +struct quals
> +{
> +  bool as_const;
> +  bool as_lvalue;
> +};
> +
> +template<typename... Args>
>  void
> -test02()
> +testTarget(Args... args)
>  {
> -  struct quals
> +  struct F
>    {
> -    bool as_const;
> -    bool as_lvalue;
> +    quals operator()(Args...) & { return { false, true }; }
> +    quals operator()(Args...) const & { return { true, true }; }
> +    quals operator()(Args...) && { return { false, false }; }
> +    quals operator()(Args...) const && { return { true, false }; }
>    };
>
> +  constexpr F f;
> +  auto g = bind_back<f>(args...);
> +  const auto& cg = g;
> +  quals q;
> +
> +  // template parameter object is always constant lvalue
> +  q = g();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = std::move(g)();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = cg();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = std::move(cg)();
> +  VERIFY( q.as_const && q.as_lvalue );
> +}
> +
> +template<typename... Args>
> +void
> +testBoundArgs(Args... args)
> +{
>    struct F
>    {
> -    quals operator()(int, int) & { return { false, true }; }
> -    quals operator()(int, int) const & { return { true, true }; }
> -    quals operator()(int, int) && { return { false, false }; }
> -    quals operator()(int, int) const && { return { true, false }; }
> +    quals operator()(Args..., int&) const { return { false, true }; }
> +    quals operator()(Args..., int const&) const { return { true, true }; }
> +    quals operator()(Args..., int&&) const { return { false, false }; }
> +    quals operator()(Args..., int const&&) const { return { true, false }; }
>    };
>
> -  // Constness and value category forwarded to the target object?
> -  { // no bound args
> -    constexpr F f;
> -    auto g = bind_back<f>();
> -    const auto& cg = g;
> -    quals q;
> -
> -    q = g(0,0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(g)(0,0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = cg(0,0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(cg)(0,0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -  }
> -  { // one bound arg
> -    constexpr F f;
> -    auto g = bind_back<f>(0);
> -    const auto& cg = g;
> -    quals q;
> -
> -    q = g(0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(g)(0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = cg(0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(cg)(0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -  }
> -  { // two bound args, the general case
> -    constexpr F f;
> -    auto g = bind_back<f>(0,0);
> -    const auto& cg = g;
> -    quals q;
> -
> -    q = g();
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(g)();
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = cg();
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(cg)();
> -    VERIFY( q.as_const && q.as_lvalue );
> -  }
> +  constexpr F f;
> +  auto g = bind_back<f>(args..., 10);
> +  const auto& cg = g;
> +  quals q;
> +
> +  // constness and value category should be forwarded to the bound objects:
> +  q = g();
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = std::move(g)();
> +  VERIFY( ! q.as_const && ! q.as_lvalue );
> +  q = cg();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = std::move(cg)();
> +  VERIFY( q.as_const && ! q.as_lvalue );
> +
> +  int i = 0;
> +  auto gr = bind_back<f>(args..., std::ref(i));
> +  const auto& cgr = gr;
> +
> +  // bound object is reference wrapper, converts to same type of reference
> +  q = gr();
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = std::move(gr)();
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = cgr();
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = std::move(cgr)();
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +
> +  auto gcr = bind_back<f>(args..., std::cref(i));
> +  const auto& cgcr = gcr;
> +
> +  q = gcr();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = std::move(gcr)();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = cgcr();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = std::move(cgcr)();
> +  VERIFY( q.as_const && q.as_lvalue );
>  }
>
> +template<typename... Args>
>  void
> -test02a()
> +testCallArgs(Args... args)
>  {
> -  struct quals
> -  {
> -    bool as_const;
> -    bool as_lvalue;
> -  };
>    struct F
>    {
> -    quals operator()(int, int&) const { return { false, true }; }
> -    quals operator()(int, int const&) const { return { true, true }; }
> -    quals operator()(int, int&&) const { return { false, false }; }
> -    quals operator()(int, int const&&) const  { return { true, false }; }
> +    quals operator()(int&, Args...) const { return { false, true }; }
> +    quals operator()(int const&, Args...) const { return { true, true }; }
> +    quals operator()(int&&, Args...) const { return { false, false }; }
> +    quals operator()(int const&&, Args...) const { return { true, false }; }
>    };
> -  constexpr F f{};
>
> -  // verify propagation
> -  auto h = bind_back<f>(10);
> -  auto const& ch = h;
> +  constexpr F f;
> +  auto g = bind_back<f>(args...);
> +  const auto& cg = g;
>    quals q;
> -
> -  q = h(0);
> -  VERIFY( !q.as_const && q.as_lvalue );
> -  q = ch(0);
> +  int i = 10;
> +  const int ci = i;
> +
> +  q = g(i);
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = g(std::move(i));
> +  VERIFY( ! q.as_const && ! q.as_lvalue );
> +  q = g(ci);
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = g(std::move(ci));
> +  VERIFY( q.as_const && ! q.as_lvalue );
> +
> +  q = cg(i);
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = cg(std::move(i));
> +  VERIFY( ! q.as_const && ! q.as_lvalue );
> +  q = cg(ci);
>    VERIFY( q.as_const && q.as_lvalue );
> -  q = std::move(h)(0);
> -  VERIFY( !q.as_const && !q.as_lvalue );
> -  q = std::move(ch)(0);
> -  VERIFY( q.as_const && !q.as_lvalue );
> +  q = cg(std::move(ci));
> +  VERIFY( q.as_const && ! q.as_lvalue );
> +
> +  struct S
> +  {
> +    int operator()(long, long, Args...) const { return 1; }
> +    int operator()(int, void*, Args...) const { return 2; }
> +  };
> +
> +  constexpr S s;
> +  // literal zero can be converted to any pointer, so (int, void*)
> +  // is best candidate
> +  VERIFY( s(0, 0, args...) == 2 );
> +  // both arguments are bound to int&&, and no longer can be
> +  // converted to pointer, (long, long) is only candidate
> +  VERIFY( bind_back<s>()(0, 0, args...) == 1 );
> +  VERIFY( bind_back<s>(args...)(0, 0) == 1 );
>  }
>
>  void
> @@ -233,26 +277,52 @@ test04()
>    return true;
>  }
>
> -struct C { int i = 0; };
> -struct D : C { D(){} D(D&&) { ++i; } };
> -int f5(D const& d1, D const& d2, D const& d3)
> -{ return d1.i + d2.i + d3.i; }
> +struct CountedArg
> +{
> +  CountedArg() = default;
> +  CountedArg(CountedArg&& f) noexcept : counter(f.counter) { ++counter; }
> +  CountedArg& operator=(CountedArg&&) = delete;
> +
> +  int counter = 0;
> +};
> +CountedArg const c;
>
> -void test05()
> +void
> +testMaterialization()
>  {
> -  // Must move arguments into capture object, not construct in place
> -  // like normal arguments.
> -  VERIFY( bind_back<f5>(D{}, D{})(D{}) == 2 );
> +  struct F
> +  {
> +    int operator()(CountedArg arg, int) const
> +    { return arg.counter; };
> +  };
> +
> +  // CountedArg is bound to rvalue-reference thus moved
> +  auto f0 = std::bind_back<F{}>();
> +  VERIFY( f0(CountedArg(), 10) == 1 );
> +
> +  auto f1 = std::bind_back<F{}>(10);
> +  VERIFY( f1(CountedArg()) == 1 );
>  }
>
>  int
>  main()
>  {
>    test01();
> -  test02();
> -  test02a();
>    test03();
>    test03a();
>    static_assert(test04());
> -  test05();
> +
> +  testTarget();
> +  testTarget(10);
> +  testTarget(10, 20, 30);
> +
> +  testBoundArgs();
> +  testBoundArgs(10);
> +  testBoundArgs(10, 20, 30);
> +
> +  testCallArgs();
> +  testCallArgs(10);
> +  testCallArgs(10, 20, 30);
> +
> +  testMaterialization();
>  }
> diff --git 
> a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc 
> b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc
> index 0839c849c0c..9eb3c432a86 100644
> --- a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc
> +++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc
> @@ -39,104 +39,145 @@ test01()
>        >);
>  }
>
> -void
> -test02()
> +struct quals
>  {
> -  struct quals
> -  {
> -    bool as_const;
> -    bool as_lvalue;
> -  };
> +  bool as_const;
> +  bool as_lvalue;
> +};
>
> +template<typename... Args>
> +void
> +testTarget(Args... args)
> +{
>    struct F
>    {
> -    quals operator()(int, int) & { return { false, true }; }
> -    quals operator()(int, int) const & { return { true, true }; }
> -    quals operator()(int, int) && { return { false, false }; }
> -    quals operator()(int, int) const && { return { true, false }; }
> +    quals operator()(Args...) & { return { false, true }; }
> +    quals operator()(Args...) const & { return { true, true }; }
> +    quals operator()(Args...) && { return { false, false }; }
> +    quals operator()(Args...) const && { return { true, false }; }
>    };
>
> -  // Constness and value category forwarded to the target object?
> -  { // no bound args
> -    constexpr F f;
> -    auto g = bind_front<f>();
> -    const auto& cg = g;
> -    quals q;
> -
> -    // Constness and value category forwarded to the target object?
> -    q = g(0,0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(g)(0,0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = cg(0,0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(cg)(0,0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -  }
> -  { // one bound arg (for when we implement that as a separate case)
> -    constexpr F f;
> -    auto g = bind_front<f>(0);
> -    const auto& cg = g;
> -    quals q;
> -
> -    // Constness and value category forwarded to the target object?
> -    q = g(0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(g)(0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = cg(0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(cg)(0);
> -    VERIFY( q.as_const && q.as_lvalue );
> -  }
> -  { // two bound args, the general case
> -    constexpr F f;
> -    auto g = bind_front<f>(0,0);
> -    const auto& cg = g;
> -    quals q;
> -
> -    q = g();
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(g)();
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = cg();
> -    VERIFY( q.as_const && q.as_lvalue );
> -    q = std::move(cg)();
> -    VERIFY( q.as_const && q.as_lvalue );
> -  }
> +  constexpr F f;
> +  auto g = bind_front<f>(args...);
> +  const auto& cg = g;
> +  quals q;
> +
> +  // template parameter object is always constant lvalue
> +  q = g();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = std::move(g)();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = cg();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = std::move(cg)();
> +  VERIFY( q.as_const && q.as_lvalue );
>  }
>
> +template<typename... Args>
>  void
> -test02a()
> +testBoundArgs(Args... args)
>  {
> -  struct quals
> +  struct F
>    {
> -    bool as_const;
> -    bool as_lvalue;
> +    quals operator()(Args..., int&) const { return { false, true }; }
> +    quals operator()(Args..., int const&) const { return { true, true }; }
> +    quals operator()(Args..., int&&) const { return { false, false }; }
> +    quals operator()(Args..., int const&&) const { return { true, false }; }
>    };
>
> +  constexpr F f;
> +  auto g = bind_front<f>(args..., 10);
> +  const auto& cg = g;
> +  quals q;
> +
> +  // constness and value category should be forwarded to the bound objects:
> +  q = g();
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = std::move(g)();
> +  VERIFY( ! q.as_const && ! q.as_lvalue );
> +  q = cg();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = std::move(cg)();
> +  VERIFY( q.as_const && ! q.as_lvalue );
> +
> +  int i = 0;
> +  auto gr = bind_front<f>(args..., std::ref(i));
> +  const auto& cgr = gr;
> +
> +  // bound object is reference wrapper, converts to same type of reference
> +  q = gr();
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = std::move(gr)();
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = cgr();
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = std::move(cgr)();
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +
> +  auto gcr = bind_front<f>(args..., std::cref(i));
> +  const auto& cgcr = gcr;
> +
> +  q = gcr();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = std::move(gcr)();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = cgcr();
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = std::move(cgcr)();
> +  VERIFY( q.as_const && q.as_lvalue );
> +}
> +
> +template<typename... Args>
> +void
> +testCallArgs(Args... args)
> +{
>    struct F
>    {
> -    quals operator()(int&, int) const { return { false, true }; }
> -    quals operator()(int const&, int) const { return { true, true }; }
> -    quals operator()(int&&, int) const { return { false, false }; }
> -    quals operator()(int const&&, int) const  { return { true, false }; }
> +    quals operator()(Args..., int&) const { return { false, true }; }
> +    quals operator()(Args..., int const&) const { return { true, true }; }
> +    quals operator()(Args..., int&&) const { return { false, false }; }
> +    quals operator()(Args..., int const&&) const { return { true, false }; }
>    };
> -  constexpr F f{};
>
> -  // verify propagation
> -  auto h = bind_front<f>(10);
> -  auto const& ch = h;
> +  constexpr F f;
> +  auto g = bind_front<f>(args...);
> +  const auto& cg = g;
>    quals q;
> -
> -  q = h(0);
> -  VERIFY( !q.as_const && q.as_lvalue );
> -  q = ch(0);
> +  int i = 10;
> +  const int ci = i;
> +
> +  q = g(i);
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = g(std::move(i));
> +  VERIFY( ! q.as_const && ! q.as_lvalue );
> +  q = g(ci);
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = g(std::move(ci));
> +  VERIFY( q.as_const && ! q.as_lvalue );
> +
> +  q = cg(i);
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = cg(std::move(i));
> +  VERIFY( ! q.as_const && ! q.as_lvalue );
> +  q = cg(ci);
>    VERIFY( q.as_const && q.as_lvalue );
> -  q = std::move(h)(0);
> -  VERIFY( !q.as_const && !q.as_lvalue );
> -  q = std::move(ch)(0);
> -  VERIFY( q.as_const && !q.as_lvalue );
> +  q = cg(std::move(ci));
> +  VERIFY( q.as_const && ! q.as_lvalue );
> +
> +  struct S
> +  {
> +    int operator()(Args..., long, long) const { return 1; }
> +    int operator()(Args..., int, void*) const { return 2; }
> +  };
> +
> +  constexpr S s;
> +  // literal zero can be converted to any pointer, so (int, void*)
> +  // is best candidate
> +  VERIFY( s(args..., 0, 0) == 2 );
> +  // both arguments are bound to int&&, and no longer can be
> +  // converted to pointer, (long, long) is only candidate
> +  VERIFY( bind_front<s>()(args..., 0, 0) == 1 );
> +  VERIFY( bind_front<s>(args...)(0, 0) == 1 );
>  }
>
>  void
> @@ -235,26 +276,53 @@ test04()
>    return true;
>  }
>
> -struct C { int i = 0; };
> -struct D : C { D(){} D(D&&) { ++i; } };
> -int f5(D const& d1, D const& d2, D const& d3)
> -{ return d1.i + d2.i + d3.i; }
> +struct CountedArg
> +{
> +  CountedArg() = default;
> +  CountedArg(CountedArg&& f) noexcept : counter(f.counter) { ++counter; }
> +  CountedArg& operator=(CountedArg&&) = delete;
> +
> +  int counter = 0;
> +};
> +CountedArg const c;
>
> -void test05()
> +void
> +testMaterialization()
>  {
> -  // Must move arguments into capture object, not construct in place
> -  // like normal arguments.
> -  VERIFY( bind_front<f5>(D{}, D{})(D{}) == 2 );
> +  struct F
> +  {
> +    int operator()(int, CountedArg arg) const
> +    { return arg.counter; };
> +  };
> +
> +  // CountedArg is bound to rvalue-reference thus moved
> +  auto f0 = std::bind_front<F{}>();
> +  VERIFY( f0(10, CountedArg()) == 1 );
> +
> +  auto f1 = std::bind_front<F{}>(10);
> +  VERIFY( f1(CountedArg()) == 1 );
>  }
>
>  int
>  main()
>  {
>    test01();
> -  test02();
> -  test02a();
>    test03();
>    test03a();
>    static_assert(test04());
> -  test05();
> +
> +  testTarget();
> +  testTarget(10);
> +  testTarget(10, 20, 30);
> +
> +  testBoundArgs();
> +  testBoundArgs(10);
> +  testBoundArgs(10, 20, 30);
> +
> +  testCallArgs();
> +  testCallArgs(10);
> +  testCallArgs(10, 20, 30);
> +
> +  testMaterialization();
> +
>  }
> diff --git a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc 
> b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc
> index d24ccf8a187..3567d679a77 100644
> --- a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc
> +++ b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc
> @@ -81,6 +81,52 @@ test07()
>    static_assert( !std::is_invocable<NotF>::value, "cannot negate" );
>  }
>
> +void
> +test08()
> +{
> +  struct quals
> +  {
> +    bool as_const;
> +    bool as_lvalue;
> +
> +    quals operator!() const
> +    { return *this; };
> +  };
> +
> +  struct F
> +  {
> +    quals operator()(int&) const { return { false, true }; }
> +    quals operator()(int const&) const { return { true, true }; }
> +    quals operator()(int&&) const { return { false, false }; }
> +    quals operator()(int const&&) const { return { true, false }; }
> +  };
> +
> +  constexpr F f;
> +  auto g = not_fn<f>();
> +  const auto& cg = g;
> +  quals q;
> +  int i = 10;
> +  const int ci = i;
> +
> +  q = g(i);
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = g(std::move(i));
> +  VERIFY( ! q.as_const && ! q.as_lvalue );
> +  q = g(ci);
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = g(std::move(ci));
> +  VERIFY( q.as_const && ! q.as_lvalue );
> +
> +  q = cg(i);
> +  VERIFY( ! q.as_const && q.as_lvalue );
> +  q = cg(std::move(i));
> +  VERIFY( ! q.as_const && ! q.as_lvalue );
> +  q = cg(ci);
> +  VERIFY( q.as_const && q.as_lvalue );
> +  q = cg(std::move(ci));
> +  VERIFY( q.as_const && ! q.as_lvalue );
> +}
> +
>  int
>  main()
>  {
> @@ -89,6 +135,7 @@ main()
>    test05();
>    test06();
>    test07();
> +  test08();
>    constexpr auto f = []{ return false; };
>    static_assert(std::not_fn<f>()());
>  }
> --
> 2.51.0
>

Reply via email to