Skip to content

Commit a24bdcf

Browse files
mystorNaios
authored andcommitted
Add option to limit empty callable propagation to known types
This approach roughly matches the one used by std::function, explicitly enumerating the types which are supported for empty propagation. Fixes #48
1 parent 035bec2 commit a24bdcf

File tree

4 files changed

+77
-10
lines changed

4 files changed

+77
-10
lines changed

Diff for: CMakeLists.txt

+8
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ if (FU2_IS_TOP_LEVEL_PROJECT)
113113
option(FU2_WITH_CPP_LATEST
114114
"Enable the highest C++ standard available for testing polyfills"
115115
OFF)
116+
option(FU2_WITH_LIMITED_EMPTY_PROPAGATION
117+
"Test limiting empty propagation to only function pointers, member pointers, std::function, and specializations of fu2::function_base"
118+
OFF)
116119

117120
if (BUILD_TESTING)
118121
if (FU2_WITH_NO_EXCEPTIONS)
@@ -125,6 +128,11 @@ if (FU2_IS_TOP_LEVEL_PROJECT)
125128
add_definitions(-DTESTS_NO_DEATH_TESTS)
126129
endif()
127130

131+
if (FU2_WITH_LIMITED_EMPTY_PROPAGATION)
132+
message(STATUS "Testing with limited empty propagation")
133+
add_definitions(-DFU2_WITH_LIMITED_EMPTY_PROPAGATION)
134+
endif()
135+
128136
add_subdirectory(test)
129137
endif()
130138
endif ()

Diff for: include/function2/function2.hpp

+30-5
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,15 @@
3535
#endif
3636
#endif
3737
#endif // FU2_WITH_DISABLED_EXCEPTIONS
38+
// - FU2_HAS_LIMITED_EMPTY_PROPAGATION
39+
#if defined(FU2_WITH_LIMITED_EMPTY_PROPAGATION)
40+
#define FU2_HAS_LIMITED_EMPTY_PROPAGATION
41+
#endif // FU2_WITH_NO_EMPTY_PROPAGATION
3842
// - FU2_HAS_NO_FUNCTIONAL_HEADER
3943
#if !defined(FU2_WITH_NO_FUNCTIONAL_HEADER) && \
4044
!defined(FU2_NO_FUNCTIONAL_HEADER) && \
41-
!defined(FU2_HAS_DISABLED_EXCEPTIONS)
45+
(!defined(FU2_HAS_DISABLED_EXCEPTIONS) || \
46+
defined(FU2_HAS_LIMITED_EMPTY_PROPAGATION))
4247
#include <functional>
4348
#else
4449
#define FU2_HAS_NO_FUNCTIONAL_HEADER
@@ -1381,13 +1386,29 @@ struct accepts_all<
13811386
void_t<std::enable_if_t<accepts_one<T, Signatures>::value>...>>
13821387
: std::true_type {};
13831388

1384-
/// Deduces to a true_type if the type T is implementing operator bool()
1385-
/// or if the type is convertible to bool directly, this also implements an
1386-
/// optimizations for function references `void(&)()` which are can never
1387-
/// be null and for such a conversion to bool would never return false.
13881389
#if defined(FU2_HAS_NO_EMPTY_PROPAGATION)
13891390
template <typename T>
13901391
struct use_bool_op : std::false_type {};
1392+
#elif defined(FU2_HAS_LIMITED_EMPTY_PROPAGATION)
1393+
/// Implementation for use_bool_op based on the behaviour of std::function,
1394+
/// propagating empty state for pointers, `std::function` and
1395+
/// `fu2::detail::function` types only.
1396+
template <typename T>
1397+
struct use_bool_op : std::false_type {};
1398+
1399+
#if !defined(FU2_HAS_NO_FUNCTIONAL_HEADER)
1400+
template <typename Signature>
1401+
struct use_bool_op<std::function<Signature>> : std::true_type {};
1402+
#endif
1403+
1404+
template <typename Config, typename Property>
1405+
struct use_bool_op<function<Config, Property>> : std::true_type {};
1406+
1407+
template <typename T>
1408+
struct use_bool_op<T*> : std::true_type {};
1409+
1410+
template <typename Class, typename T>
1411+
struct use_bool_op<T Class::*> : std::true_type {};
13911412
#else
13921413
template <typename T, typename = void>
13931414
struct has_bool_op : std::false_type {};
@@ -1400,6 +1421,10 @@ struct has_bool_op<T, void_t<decltype(bool(std::declval<T>()))>>
14001421
#endif
14011422
};
14021423

1424+
/// Deduces to a true_type if the type T is implementing operator bool()
1425+
/// or if the type is convertible to bool directly, this also implements an
1426+
/// optimizations for function references `void(&)()` which are can never
1427+
/// be null and for such a conversion to bool would never return false.
14031428
template <typename T>
14041429
struct use_bool_op : has_bool_op<T> {};
14051430

Diff for: test/empty-function-call-test.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,12 @@ TYPED_TEST(AllEmptyFunctionCallTests, CallPropagatesEmptyCustom) {
9696
{
9797
typename TestFixture::template left_t<void(some_tag)> fn(
9898
my_callable_empty{});
99+
#if defined(FU2_HAS_LIMITED_EMPTY_PROPAGATION) || \
100+
defined(FU2_HAS_NO_EMPTY_PROPAGATION)
101+
ASSERT_FALSE(fn.empty());
102+
#else
99103
ASSERT_TRUE(fn.empty());
104+
#endif
100105
}
101106
}
102107
#endif // FU2_HAS_NO_EMPTY_PROPAGATION

Diff for: test/regressions.cpp

+34-5
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,11 @@ TEST(regression_tests, can_assign_nonowning_noncopyable_view) {
127127

128128
static fu2::unique_function<void()> issue_14_create() {
129129
// remove the commented dummy capture to be compilable
130-
fu2::unique_function<void()>
131-
func = [i = std::vector<std::vector<std::unique_ptr<int>>>{}
132-
// ,dummy = std::unique_ptr<int>()
133-
](){
134-
// ...
130+
fu2::unique_function<void()> func =
131+
[i = std::vector<std::vector<std::unique_ptr<int>>>{}
132+
// ,dummy = std::unique_ptr<int>()
133+
]() {
134+
// ...
135135
};
136136

137137
return std::move(func);
@@ -199,6 +199,35 @@ TEST(regression_tests, unique_non_copyable) {
199199
ASSERT_EQ(view(), 5);
200200
}*/
201201

202+
// https://github.com/Naios/function2/issues/48
203+
// -Waddress warning generated for non-capturing lambdas on gcc <= 9.2 #48
204+
TEST(regression_tests, no_address_warning_in_constexpr_lambda) {
205+
using fun_t = fu2::function<int()>;
206+
fun_t f([] { return 3836474; });
207+
208+
ASSERT_EQ(f(), 3836474);
209+
}
210+
211+
struct custom_falsy_invocable {
212+
operator bool() const {
213+
return false;
214+
}
215+
int operator()() const {
216+
return 0;
217+
}
218+
};
219+
220+
TEST(regression_tests, custom_falsy_invocable) {
221+
fu2::function<int()> f(custom_falsy_invocable{});
222+
223+
#if defined(FU2_HAS_LIMITED_EMPTY_PROPAGATION) || \
224+
defined(FU2_HAS_NO_EMPTY_PROPAGATION)
225+
ASSERT_TRUE(static_cast<bool>(f));
226+
#else
227+
ASSERT_FALSE(static_cast<bool>(f));
228+
#endif
229+
}
230+
202231
namespace issue_35 {
203232
class ref_obj {
204233
public:

0 commit comments

Comments
 (0)