Commit 22fdc78a authored by Pádraig Ó Conbhuí's avatar Pádraig Ó Conbhuí
Browse files

Fix forwarding mistake in implementation, add tests for perfect returns

parent 2649568e
Pipeline #542 passed with stage
in 59 seconds
......@@ -16,7 +16,7 @@ template<typename Callback, typename ArgsTuple>
constexpr decltype(auto) visit_bools_impl(Callback&& callback, ArgsTuple&& args) {
return invoke_tuple(
std::make_index_sequence<std::tuple_size<ArgsTuple>::value>(),
callback, args
std::forward<Callback>(callback), std::forward<ArgsTuple>(args)
);
}
......
......@@ -6,31 +6,41 @@
int static_value(std::true_type) { return 1; }
int static_value(std::false_type) { return 0; }
template<typename T> T basic_declval();
TEST_CASE("visit_bools", "[visit_bools]") {
bool a = GENERATE(true, false);
bool b = GENERATE(true, false);
bool c = GENERATE(true, false);
SECTION("visit_bools with only bools") {
auto value = visit_bools::visit_bools([](auto a, auto b, auto c) {
return 2*2*static_value(a)
+ 2*static_value(b)
+ static_value(c);
}, a, b, c);
REQUIRE(value == (2*2*(a?1:0) + 2*(b?1:0) + (c?1:0)));
SECTION("visit_bools converts runtime bools to compile-time types") {
auto value = visit_bools::visit_bools(
[&](auto static_a, auto static_b, auto static_c) {
REQUIRE(a == static_a);
REQUIRE(b == static_b);
REQUIRE(c == static_c);
return 100*static_value(static_a)
+ 10*static_value(static_b)
+ static_value(static_c);
},
a, b, c
);
REQUIRE(value == (100*(a?1:0) + 10*(b?1:0) + (c?1:0)));
}
SECTION("visit_bools with mixed values") {
float d = GENERATE(10.1f, 20.2f);
float d = GENERATE(0.1f, 0.2f);
float value;
SECTION("mixed first") {
auto tmp_value = visit_bools::visit_bools(
[](auto d, auto a, auto b, auto c) {
return 2*2*static_value(a)
+ 2*static_value(b)
return 100*static_value(a)
+ 10*static_value(b)
+ static_value(c)
+ d;
},
......@@ -45,8 +55,8 @@ TEST_CASE("visit_bools", "[visit_bools]") {
SECTION("mixed second") {
auto tmp_value = visit_bools::visit_bools(
[](auto a, auto d, auto b, auto c) {
return 2*2*static_value(a)
+ 2*static_value(b)
return 100*static_value(a)
+ 10*static_value(b)
+ static_value(c)
+ d;
},
......@@ -61,8 +71,8 @@ TEST_CASE("visit_bools", "[visit_bools]") {
SECTION("mixed last") {
auto tmp_value = visit_bools::visit_bools(
[](auto a, auto b, auto c, auto d) {
return 2*2*static_value(a)
+ 2*static_value(b)
return 100*static_value(a)
+ 10*static_value(b)
+ static_value(c)
+ d;
},
......@@ -74,6 +84,118 @@ TEST_CASE("visit_bools", "[visit_bools]") {
STATIC_REQUIRE(std::is_same<decltype(tmp_value), float>::value);
}
REQUIRE(value == (2*2*(a?1:0) + 2*(b?1:0) + (c?1:0)) + d);
REQUIRE(value == (100*(a?1:0) + 10*(b?1:0) + (c?1:0)) + d);
}
SECTION("visit_bools perfectly forwards arguments and perfectly returns") {
// A type which fails when any public constructor is called.
// Use fail_on_construction::make() to construct an instance.
class fail_on_construction {
private:
struct private_construction_t {};
fail_on_construction(private_construction_t) {}
public:
static fail_on_construction make() {
return {private_construction_t{}};
}
fail_on_construction() {
FAIL("Default constructor called");
}
~fail_on_construction() {
SUCCEED();
}
fail_on_construction(const fail_on_construction&) {
FAIL("Copy constructor called");
}
fail_on_construction& operator=(const fail_on_construction&) {
FAIL("Copy assignment called");
return *this;
}
fail_on_construction(fail_on_construction&&) {
FAIL("Move constructor called");
}
fail_on_construction& operator=(fail_on_construction&&) {
FAIL("Move assignment called");
return *this;
}
};
SECTION("rvalue references") {
visit_bools::visit_bools([](const fail_on_construction& f) {
SUCCEED();
}, fail_on_construction::make());
fail_on_construction f = fail_on_construction::make();
visit_bools::visit_bools([](fail_on_construction&& f) {
SUCCEED();
}, std::move(f));
visit_bools::visit_bools([](const fail_on_construction& f) {
SUCCEED();
}, std::move(f));
}
SECTION("lvalue references") {
fail_on_construction f = fail_on_construction::make();
visit_bools::visit_bools([](fail_on_construction& f) {
SUCCEED();
}, f);
visit_bools::visit_bools([](const fail_on_construction& f) {
SUCCEED();
}, f);
}
SECTION("perfect returns") {
visit_bools::visit_bools([]() {
return fail_on_construction::make();
});
fail_on_construction f = visit_bools::visit_bools([]() {
return fail_on_construction::make();
});
STATIC_REQUIRE(std::is_same<
decltype(visit_bools::visit_bools(basic_declval<int>)), int
>::value);
STATIC_REQUIRE(std::is_same<
decltype(visit_bools::visit_bools(std::declval<int&>)), int&
>::value);
STATIC_REQUIRE(std::is_same<
decltype(visit_bools::visit_bools(std::declval<const int&>)),
const int&
>::value);
STATIC_REQUIRE(std::is_same<
decltype(visit_bools::visit_bools(std::declval<int&&>)),
int&&
>::value);
STATIC_REQUIRE(std::is_same<
decltype(
visit_bools::visit_bools(std::declval<volatile int&>)
),
volatile int&
>::value);
STATIC_REQUIRE(std::is_same<
decltype(
visit_bools::visit_bools(std::declval<const volatile int&>)
),
const volatile int&
>::value);
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment