Dobiasd / FunctionalPlus

Functional Programming Library for C++. Write concise and readable C++ code.
http://www.editgym.com/fplus-api-search/
Boost Software License 1.0
2.07k stars 168 forks source link

Added noexcept variants to function traits #298

Closed LuSo58 closed 3 months ago

LuSo58 commented 3 months ago

When using function_traits with callable items that are noexcept, no specialization would match. Here is a simple reproduction case for this.

#include <iostream>
#include <functional>

#include "fplus/fplus.hpp"

template<typename F, typename T = typename fplus::utils::function_traits<F>::template arg<0>::type>
auto forward(F f) {
  return [f](auto x) {
    auto ret = f(x);
    return ret;
  };
}

class klass {
  public:
    int x;

    int normal() const {
      return x;
    }

    int noexc() const noexcept {
      return x;
    }
};

int half(int x) {
  return x / 2;
}

int half_noexc(int x) noexcept {
  return x / 2;
}

struct functor {
  int operator()(int x) {
    return x + 5;
  }
};

struct functor_noexc {
  int operator()(int x) noexcept {
    return x + 5;
  }
};

int main() {
  klass k = {42};
  std::cout << forward(std::mem_fn(&klass::normal))(k) << std::endl; // OK
  std::cout << forward(std::mem_fn(&klass::noexc))(k) << std::endl; // Will not compile
  std::cout << forward(half)(42) << std::endl; // OK
  std::cout << forward(half_noexc)(42) << std::endl; // Will not compile
  std::cout << forward(functor())(42) << std::endl; // OK
  std::cout << forward(functor_noexc())(42) << std::endl; // Will not compile
  auto lambda = [](int x) {
    return x + 10;
  };
  auto lambda_noexc = [](int x) noexcept {
    return x + 10;
  };
  std::cout << forward(lambda)(42) << std::endl; // OK
  std::cout << forward(lambda_noexc)(42) << std::endl; // Will not compile
}

EDIT

Sorry for recreating the pull request. I finally figured out the CI and also wanted to rebase the branch to tidy the commits.

This version should compile for all compilers in the CI.

LuSo58 commented 3 months ago

After looking into it, I found that noexcept was not initially part of the type system, but just a marker. See __cpp_noexcept_function_type at https://en.cppreference.com/w/cpp/feature_test. I changed the guard macros accordingly.

Still compiles and passes CI. See "Actions" in the fork repo.

This is probably how it's supposed to be if-ed out :sweat_smile:

Dobiasd commented 3 months ago

The noexcept specifier is very useful in C++, so I'm delighted FunctionalPlus now supports it. :rocket:

Thanks a lot for this amazing contribution (and the nice test coverage)! :heart: