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 11, 2024
1 parent 8a8486d commit 09fef2e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
4 changes: 2 additions & 2 deletions include/unifex/bind_back.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,10 @@ 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
57 changes: 57 additions & 0 deletions test/let_done_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,60 @@ TEST(TransformDone, WithValue) {
EXPECT_TRUE(multiple.has_value());
EXPECT_EQ(*multiple, std::tuple(42, 1, 2));
}

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

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

EXPECT_TRUE(freeFunction.has_value());
EXPECT_EQ(*freeFunction, std::tuple(42, 1, 2));

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

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

EXPECT_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();

EXPECT_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();

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

0 comments on commit 09fef2e

Please sign in to comment.