Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move use of declval into decltype. #3

Merged
merged 2 commits into from
Feb 23, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 19 additions & 22 deletions test/initial_draft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <stlab/concurrency/await.hpp>
#include <stlab/concurrency/future.hpp>

#define STLAB_FWD(x) std::forward<decltype(x)>(x)

Check failure on line 16 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, llvm-15.0.2, Ninja Multi-Config, Debug, OFF, OFF)

function-like macro 'STLAB_FWD' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage,-warnings-as-errors]

Check failure on line 16 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, gcc-11, Ninja Multi-Config, Debug, OFF, OFF)

function-like macro 'STLAB_FWD' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage,-warnings-as-errors]

Check failure on line 16 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, gcc-11, Ninja Multi-Config, Release, OFF, OFF)

function-like macro 'STLAB_FWD' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage,-warnings-as-errors]

Check failure on line 16 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, llvm-15.0.2, Ninja Multi-Config, Release, OFF, OFF)

function-like macro 'STLAB_FWD' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage,-warnings-as-errors]

/*

If exception inside of a segment _apply_ function throws an exception then the exception must be
Expand All @@ -30,7 +32,7 @@
*/

template <class Applicator, class... Fs>
class segment {

Check failure on line 35 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, llvm-15.0.2, Ninja Multi-Config, Debug, OFF, OFF)

class 'segment' defines a copy constructor, a copy assignment operator, a move constructor and a move assignment operator but does not define a destructor [cppcoreguidelines-special-member-functions,hicpp-special-member-functions,-warnings-as-errors]

Check failure on line 35 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, gcc-11, Ninja Multi-Config, Debug, OFF, OFF)

class 'segment' defines a copy constructor, a copy assignment operator, a move constructor and a move assignment operator but does not define a destructor [cppcoreguidelines-special-member-functions,hicpp-special-member-functions,-warnings-as-errors]

Check failure on line 35 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, gcc-11, Ninja Multi-Config, Release, OFF, OFF)

class 'segment' defines a copy constructor, a copy assignment operator, a move constructor and a move assignment operator but does not define a destructor [cppcoreguidelines-special-member-functions,hicpp-special-member-functions,-warnings-as-errors]

Check failure on line 35 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, llvm-15.0.2, Ninja Multi-Config, Release, OFF, OFF)

class 'segment' defines a copy constructor, a copy assignment operator, a move constructor and a move assignment operator but does not define a destructor [cppcoreguidelines-special-member-functions,hicpp-special-member-functions,-warnings-as-errors]
std::tuple<Fs...> _functions;
Applicator _apply;

Expand All @@ -49,13 +51,13 @@
The basic operations should follow those from C++ lambdas, for now default everything.
and see if the compiler gets it correct.
*/
explicit segment(const segment&) = default;

Check failure on line 54 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, llvm-15.0.2, Ninja Multi-Config, Debug, OFF, OFF)

copy constructor should not be declared explicit [hicpp-explicit-conversions,-warnings-as-errors]

Check failure on line 54 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, gcc-11, Ninja Multi-Config, Debug, OFF, OFF)

copy constructor should not be declared explicit [hicpp-explicit-conversions,-warnings-as-errors]

Check failure on line 54 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, gcc-11, Ninja Multi-Config, Release, OFF, OFF)

copy constructor should not be declared explicit [hicpp-explicit-conversions,-warnings-as-errors]

Check failure on line 54 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, llvm-15.0.2, Ninja Multi-Config, Release, OFF, OFF)

copy constructor should not be declared explicit [hicpp-explicit-conversions,-warnings-as-errors]
segment(segment&&) noexcept = default;
segment& operator=(const segment&) = default;
segment& operator=(segment&&) noexcept = default;

template <class F>
auto append(F&& f) && {

Check failure on line 60 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, llvm-15.0.2, Ninja Multi-Config, Debug, OFF, OFF)

parameter name 'f' is too short, expected at least 3 characters [readability-identifier-length,-warnings-as-errors]

Check failure on line 60 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, gcc-11, Ninja Multi-Config, Debug, OFF, OFF)

parameter name 'f' is too short, expected at least 3 characters [readability-identifier-length,-warnings-as-errors]

Check failure on line 60 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, gcc-11, Ninja Multi-Config, Release, OFF, OFF)

parameter name 'f' is too short, expected at least 3 characters [readability-identifier-length,-warnings-as-errors]

Check failure on line 60 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, llvm-15.0.2, Ninja Multi-Config, Release, OFF, OFF)

parameter name 'f' is too short, expected at least 3 characters [readability-identifier-length,-warnings-as-errors]
return chains::segment{std::move(_apply), std::tuple_cat(std::move(_functions),
std::tuple{std::forward<F>(f)})};
}
Expand All @@ -80,7 +82,7 @@

std::move(_apply)(
[_f = tuple_compose(std::move(_functions)),
_receiver = receiver](auto&&... args) mutable noexcept {

Check warning on line 85 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, gcc-11, Ninja Multi-Config, Release, ON, OFF)

declaration of ‘auto:60&& ... args’ shadows a parameter [-Wshadow]

Check warning on line 85 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Test (ubuntu-20.04, gcc-11, Ninja Multi-Config, Debug, ON, OFF)

declaration of ‘auto:60&& ... args’ shadows a parameter [-Wshadow]

Check warning on line 85 in test/initial_draft.cpp

View workflow job for this annotation

GitHub Actions / Analyze (cpp, gcc-11, Ninja Multi-Config, Debug, ON)

declaration of ‘auto:60&& ... args’ shadows a parameter [-Wshadow]
if (_receiver.canceled()) return;
try {
std::move(_f)(std::forward<decltype(args)>(args)...);
Expand All @@ -92,6 +94,16 @@
}
};

namespace detail {

/// Apply a recursive lambda to each element in the tuple-like Segments.
template <class Fold, class Segments>
constexpr auto fold_over(Fold fold, Segments&& segments) {
return std::apply([fold](auto&&... links) { return fold(fold, STLAB_FWD(links)...); }, STLAB_FWD(segments));
}

Check warning on line 103 in test/initial_draft.cpp

View check run for this annotation

Codecov / codecov/patch

test/initial_draft.cpp#L103

Added line #L103 was not covered by tests

} // namespace detail

template <class Segment, class... Args>
using segment_result_type =
decltype(std::declval<Segment>().result_type_helper(std::declval<Args>()...));
Expand All @@ -100,32 +112,16 @@
simplify this code by handing the multi-argument case earlier (somehow).
*/

#define STLAB_FWD(x) std::forward<decltype(x)>(x)

template <class Tail, class Applicator, class... Fs>
class chain {
Tail _tail;
segment<Applicator, Fs...> _head;

/// Apply a recursive lambda to each element in _tail, followed by _head.
template <class F>
auto fold_over(F fold) && {
return std::apply([fold](auto&&... links) { return fold(fold, STLAB_FWD(links)...); },
std::tuple_cat(std::move(_tail), std::tuple(std::move(_head))));
}

template <class F>
static consteval auto static_fold_over(F fold) {
return std::apply([fold](auto&&... links) { return fold(fold, STLAB_FWD(links)...); },
std::tuple_cat(std::declval<Tail>(),
std::tuple(std::declval<segment<Applicator, Fs...>>())));
}

/// Return a lambda with the signature of
/// head( tail<n>( tail<1>( tail<0>( auto&& args... ) ) ) )
/// for computing the result type of this chain.
static consteval auto result_type_helper() {
return static_fold_over([](auto fold, auto&& first, auto&&... rest) {
static consteval auto result_type_helper(Tail&& tail, segment<Applicator, Fs...>&& head) {
return detail::fold_over([](auto fold, auto&& first, auto&&... rest) {
if constexpr (sizeof...(rest) == 0) {
return [_segment = STLAB_FWD(first)](auto&&... args) mutable {
return std::move(_segment).result_type_helper(STLAB_FWD(args)...);
Expand All @@ -136,12 +132,12 @@
return std::move(_segment).result_type_helper(STLAB_FWD(args)...);
};
}
});
}, std::tuple_cat(std::move(tail), std::tuple{std::move(head)}));
}

template <class R>
auto expand(const R& receiver) && {
return std::move(*this).fold_over([receiver](auto fold, auto&& first, auto&&... rest) {
return detail::fold_over([receiver](auto fold, auto&& first, auto&&... rest) {
if constexpr (sizeof...(rest) == 0) {
return [receiver,
_segment = STLAB_FWD(first).append(receiver)](auto&&... args) mutable {
Expand All @@ -153,12 +149,13 @@
return std::move(_segment).invoke(receiver, STLAB_FWD(args)...);
};
}
});
}, std::tuple_cat(std::move(_tail), std::tuple{std::move(_head)}));
}

public:
template <class... Args>
using result_type = decltype(result_type_helper()(std::declval<Args>()...));
using result_type =
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sean-parent this is my best attempt at getting result_type to work, so far. If I try to use result_type_helper like this:

    template <class... Args>
    using result_type = 
      decltype(std::declval<chain>().result_type_helper()(std::declval<Args>()...));

We fail by attempting to access a member of an incomplete type. Not sure if there's a cleaner way around this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm liking it! What more would you like to do on this before I push.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're happy, I'm happy. Feel free to merge.

decltype(result_type_helper(std::declval<Tail>(), std::declval<segment<Applicator, Fs...>>())(std::declval<Args>()...));

explicit chain(Tail&& tail, segment<Applicator, Fs...>&& head)
: _tail{std::move(tail)}, _head{std::move(head)} {}
Expand Down
Loading