Skip to content

Commit

Permalink
Add support for function references (free and static member) in bind_…
Browse files Browse the repository at this point in the history
…back

The following program does not compile: https://godbolt.org/z/WfhEc51dY
But if we replace the function reference with a lambda, it does: https://godbolt.org/z/jrhTY4nse
Constructing a std::tuple with a function type fails but function pointers are allowed.
We instantiate _result with std::decay_t<ArgN>... which maps function references to function pointers
and then the corresponding std::tuple instantiation does not fail to compile. The problem with the
existing code is that, in order to instantiate std::tuple<std::decay_t<ArgN>...>, we first constructed a
std::tuple<ArgN> and passed it over. If instead we construct a std::tuple<std::decay_t<ArgN>...>
with the function arguments, they will be converted to function pointers and the std::tuple instantiation
will compile.
  • Loading branch information
denizevrenci committed Apr 12, 2024
1 parent f58c1e3 commit 28dd29e
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
6 changes: 4 additions & 2 deletions include/unifex/bind_back.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,12 @@ inline const struct _fn {
template <typename Cpo, typename... ArgN>
constexpr auto operator()(Cpo cpo, ArgN&&... argN) const
noexcept(noexcept(_result<Cpo, std::decay_t<ArgN>...>{
{}, (Cpo &&) cpo, std::tuple{(ArgN &&) argN...}}))
{},
(Cpo &&) cpo,
std::tuple<std::decay_t<ArgN>...>{(ArgN &&) argN...}}))
-> _result<Cpo, std::decay_t<ArgN>...> {
return _result<Cpo, std::decay_t<ArgN>...>{
{}, (Cpo &&) cpo, std::tuple{(ArgN &&) argN...}};
{}, (Cpo &&) cpo, std::tuple<std::decay_t<ArgN>...>{(ArgN &&) argN...}};
}
} bind_back{};

Expand Down
49 changes: 49 additions & 0 deletions test/let_done_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,52 @@ TEST(TransformDone, WithValue) {
ASSERT_TRUE(multiple.has_value());
EXPECT_EQ(*multiple, std::tuple(42, 1, 2));
}

static auto just42() {
return just(42);
}

TEST(TransformDone, WithFunction) {
auto freeFunction = just_done() | let_done(just42) | sync_wait();

ASSERT_TRUE(freeFunction.has_value());
EXPECT_EQ(*freeFunction, 42);

struct StaticMemberFunction {
static auto call() { return just(42, 1, 2); }
};

auto staticMemberFunction =
just_done() | let_done(StaticMemberFunction::call) | sync_wait();

ASSERT_TRUE(staticMemberFunction.has_value());
EXPECT_EQ(*staticMemberFunction, std::tuple(42, 1, 2));
}

TEST(TransformDone, WithExplicitCopyMove) {
struct ExplicitCopy {
ExplicitCopy() = default;

explicit ExplicitCopy(const ExplicitCopy& other) = default;

auto operator()() { return just(42, 1, 2); }
};

auto explicitCopy = just_done() | let_done(ExplicitCopy{}) | sync_wait();

ASSERT_TRUE(explicitCopy.has_value());
EXPECT_EQ(*explicitCopy, std::tuple(42, 1, 2));

struct ExplicitMove {
ExplicitMove() = default;

explicit ExplicitMove(ExplicitMove&& other) = default;

auto operator()() { return just(42, 1, 2); }
};

auto explicitMove = just_done() | let_done(ExplicitMove{}) | sync_wait();

ASSERT_TRUE(explicitMove.has_value());
EXPECT_EQ(*explicitMove, std::tuple(42, 1, 2));
}

0 comments on commit 28dd29e

Please sign in to comment.