blob: 9e48e60926e0907aac550d4edf4712c0dddc51f6 [file] [log] [blame]
// Copyright (C) 2014-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
#include <functional>
#include <testsuite_hooks.h>
#ifndef __cpp_lib_bind_front
# error "Feature test macro for bind_front is missing"
#elif __cpp_lib_bind_front < 201902L
# error "Feature test macro for bind_front has wrong value"
#endif
using std::bind_front;
using std::is_same_v;
using std::is_invocable_v;
using std::is_invocable_r_v;
void
test01()
{
struct F { void operator()() {} };
// Arguments should be decayed:
static_assert(std::is_same_v<
decltype(bind_front(std::declval<F>(), std::declval<int>())),
decltype(bind_front(std::declval<F&>(), std::declval<int&>()))
>);
static_assert(std::is_same_v<
decltype(bind_front(std::declval<F>(), std::declval<int>())),
decltype(bind_front(std::declval<const F&>(), std::declval<const int&>()))
>);
// Reference wrappers should be handled:
static_assert(!std::is_same_v<
decltype(bind_front(std::declval<F>(), std::declval<int&>())),
decltype(bind_front(std::declval<F>(), std::ref(std::declval<int&>())))
>);
static_assert(!std::is_same_v<
decltype(bind_front(std::declval<F>(), std::declval<const int&>())),
decltype(bind_front(std::declval<F>(), std::cref(std::declval<int&>())))
>);
static_assert(!std::is_same_v<
decltype(bind_front(std::declval<F>(), std::ref(std::declval<int&>()))),
decltype(bind_front(std::declval<F>(), std::cref(std::declval<int&>())))
>);
}
void
test02()
{
struct quals
{
bool as_const;
bool as_lvalue;
};
struct F
{
quals operator()() & { return { false, true }; }
quals operator()() const & { return { true, true }; }
quals operator()() && { return { false, false }; }
quals operator()() const && { return { true, false }; }
};
F f;
auto g = bind_front(f);
const auto& cg = g;
quals q;
// constness and value category should be forwarded to the target object:
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 );
}
void
test03()
{
struct F
{
int& operator()(int& i, void*) { return i; }
void* operator()(int, void* p) const { return p; }
};
int i = 5;
void* vp = &vp; // arbitrary void* value
auto g1 = bind_front(F{}, i); // call wrapper has bound arg of type int
using G1 = decltype(g1);
// Invoking G1& will pass g1's bound arg as int&, so calls first overload:
static_assert(is_invocable_r_v<int&, G1&, void*>);
// Invoking const G1& or G&& calls second overload:
static_assert(is_invocable_r_v<void*, const G1&, void*>);
static_assert(is_invocable_r_v<void*, G1&&, void*>);
void* p1 = static_cast<G1&&>(g1)(vp);
VERIFY( p1 == vp );
auto g2 = bind_front(F{}, std::ref(i)); // bound arg of type int&
using G2 = decltype(g2);
// Bound arg always forwarded as int& even from G2&& or const G2&
static_assert(is_invocable_r_v<int&, G2&, void*>);
static_assert(is_invocable_r_v<int&, G2&&, void*>);
// But cannot call first overload on const G2:
static_assert(is_invocable_r_v<void*, const G2&, void*>);
static_assert(is_invocable_r_v<void*, const G2&&, void*>);
int& i2 = g2(vp);
VERIFY( &i2 == &i );
int& i2r = static_cast<G2&&>(g2)(vp);
VERIFY( &i2r == &i );
void* p2 = const_cast<const G2&>(g2)(vp);
VERIFY( p2 == vp );
auto g3 = bind_front(F{}, std::cref(i)); // bound arg of type const int&
using G3 = decltype(g3);
// Bound arg always forwarded as const int& so can only call second overload:
static_assert(is_invocable_r_v<void*, G3&, void*>);
static_assert(is_invocable_r_v<void*, G3&&, void*>);
static_assert(is_invocable_r_v<void*, const G3&, void*>);
static_assert(is_invocable_r_v<void*, const G3&&, void*>);
auto g4 = bind_front(g2, nullptr);
using G4 = decltype(g4);
static_assert(is_invocable_r_v<int&, G4&>);
static_assert(is_invocable_r_v<int&, G4&&>);
static_assert(is_invocable_r_v<void*, const G4&>);
static_assert(is_invocable_r_v<void*, const G4&&>);
}
int f(int i, int j, int k) { return i + j + k; }
void
test04()
{
auto g = bind_front(f);
VERIFY( g(1, 2, 3) == 6 );
auto g1 = bind_front(f, 1);
VERIFY( g1(2, 3) == 6 );
VERIFY( bind_front(g, 1)(2, 3) == 6 );
auto g2 = bind_front(f, 1, 2);
VERIFY( g2(3) == 6 );
VERIFY( bind_front(g1, 2)(3) == 6 );
auto g3 = bind_front(f, 1, 2, 3);
VERIFY( g3() == 6 );
VERIFY( bind_front(g2, 3)() == 6 );
}
int
main()
{
test01();
test02();
test03();
test04();
}