Skip to content
Snippets Groups Projects
Commit 1ab4d91f authored by Carsten Gräser's avatar Carsten Gräser
Browse files

Allow returning references in Std::visit()

parent 07b27021
Branches
Tags
1 merge request!664Allow returning references in Std::visit()
Pipeline #18289 passed
......@@ -338,55 +338,21 @@ namespace Impl {
* in this variant.
*/
template<typename F>
auto visit(F&& func) {
using namespace Dune::Hybrid;
using Result = decltype(func(unions_.getByIndex(std::integral_constant<size_t, 0>())));
return ifElse(std::is_same<Result, void>(), [&, this](auto id) {
constexpr auto tsize = size_;
Dune::Hybrid::forEach(Dune::Hybrid::integralRange(std::integral_constant<size_t, tsize>()), [&](auto i) {
if (i==this->index_)
func(id(unions_).getByIndex(std::integral_constant<size_t, i>()));
});
return;},
[&func,this](auto id) {
constexpr auto tsize = size_;
auto result = std::unique_ptr<Result>();
Dune::Hybrid::forEach(Dune::Hybrid::integralRange(std::integral_constant<size_t, tsize>()), [&, this](auto i) {
if (i==this->index_)
result = std::make_unique<Result>(func(id(this->unions_).getByIndex(std::integral_constant<size_t, i>())));
});
return *result;
});
decltype(auto) visit(F&& func) {
auto dummyElseBranch = [&]() -> decltype(auto) { return func(this->get<0>());};
auto indices = std::make_index_sequence<size_>{};
return Hybrid::switchCases(indices, index(), [&](auto staticIndex) -> decltype(auto) {
return func(this->template get<decltype(staticIndex)::value>());
}, dummyElseBranch);
}
template<typename F>
auto visit(F&& func) const {
using namespace Dune::Hybrid;
using Result = decltype(func(unions_.getByIndex(std::integral_constant<size_t, 0>())));
return ifElse(std::is_same<Result, void>(), [&, this](auto id) {
constexpr auto tsize = size_;
Dune::Hybrid::forEach(Dune::Hybrid::integralRange(std::integral_constant<size_t, tsize>()), [&](auto i) {
if (i==this->index_)
func(id(unions_).getByIndex(std::integral_constant<size_t, i>()));
});
return;},
[&func,this](auto id) {
constexpr auto tsize = size_;
auto result = std::unique_ptr<Result>();
Dune::Hybrid::forEach(Dune::Hybrid::integralRange(std::integral_constant<size_t, tsize>()), [&, this](auto i) {
if (i==this->index_)
result = std::make_unique<Result>(func(id(this->unions_).getByIndex(std::integral_constant<size_t, i>())));
});
return *result;
});
decltype(auto) visit(F&& func) const {
auto dummyElseBranch = [&]() -> decltype(auto) { return func(this->get<0>());};
auto indices = std::make_index_sequence<size_>{};
return Hybrid::switchCases(indices, index(), [&](auto staticIndex) -> decltype(auto) {
return func(this->template get<decltype(staticIndex)::value>());
}, dummyElseBranch);
}
/** \brief Check if a given type is the one that is currently active in the variant. */
......@@ -428,12 +394,12 @@ namespace Impl {
}
template<typename F, typename... T>
auto visit(F&& visitor, variant<T...>& var) {
decltype(auto) visit(F&& visitor, variant<T...>& var) {
return var.visit(std::forward<F>(visitor));
}
template<typename F, typename... T>
auto visit(F&& visitor, const variant<T...>& var) {
decltype(auto) visit(F&& visitor, const variant<T...>& var) {
return var.visit(std::forward<F>(visitor));
}
......
......@@ -87,6 +87,15 @@ Dune::TestSuite testVariant() {
suite.check(Std::visit(size, constv2)== 2, "Test const visit");
suite.check(Std::get_if<V2>(&constv2) != nullptr, "Test const get_if");
// Check visitor returning lvalue
using A = struct { int j; int i;};
using B = struct { int i;};
Std::variant<A,B> variant3;
variant3 = A{1,2};
Std::visit([](auto&& value) -> decltype(auto) { return (value.i); }, variant3) = 42;
suite.check(Std::visit([](auto&& value) { return value.i;}, variant3)== 42, "Std::visit returning lvalue");
/// test copy and move construction/assignment
{
auto variant_copy_constructed = variant2;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment