-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
absl::Overload()
which returns a functor that provides overloads ba…
…sed on the functors passed to it. PiperOrigin-RevId: 568476251 Change-Id: Ic625c9b5300d1db496979c178ca1e655581f9276
- Loading branch information
1 parent
d53ca3b
commit f4c6246
Showing
5 changed files
with
256 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright 2023 The Abseil Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// ----------------------------------------------------------------------------- | ||
// File: overload.h | ||
// ----------------------------------------------------------------------------- | ||
// | ||
// `absl::Overload()` returns a functor that provides overloads based on the | ||
// functors passed to it. | ||
// Before using this function, consider whether named function overloads would | ||
// be a better design. | ||
// One use case for this is locally defining visitors for `std::visit` inside a | ||
// function using lambdas. | ||
|
||
// Example: Using `absl::Overload` to define a visitor for `std::variant`. | ||
// | ||
// std::variant<int, std::string, double> v(int{1}); | ||
// | ||
// assert(std::visit(absl::Overload( | ||
// [](int) -> absl::string_view { return "int"; }, | ||
// [](const std::string&) -> absl::string_view { | ||
// return "string"; | ||
// }, | ||
// [](double) -> absl::string_view { return "double"; }), | ||
// v) == "int"); | ||
// | ||
// Note: This requires C++17. | ||
|
||
#ifndef ABSL_FUNCTIONAL_OVERLOAD_H_ | ||
#define ABSL_FUNCTIONAL_OVERLOAD_H_ | ||
|
||
#include "absl/base/config.h" | ||
#include "absl/meta/type_traits.h" | ||
|
||
namespace absl { | ||
ABSL_NAMESPACE_BEGIN | ||
|
||
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ | ||
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L | ||
|
||
template <int&... ExplicitArgumentBarrier, typename... T> | ||
auto Overload(T&&... ts) { | ||
struct OverloadImpl : absl::remove_cvref_t<T>... { | ||
using absl::remove_cvref_t<T>::operator()...; | ||
}; | ||
return OverloadImpl{std::forward<T>(ts)...}; | ||
} | ||
#else | ||
namespace functional_internal { | ||
template <typename T> | ||
constexpr bool kDependentFalse = false; | ||
} | ||
|
||
template <typename Dependent = int, typename... T> | ||
auto Overload(T&&...) { | ||
static_assert(functional_internal::kDependentFalse<Dependent>, | ||
"Overload is only usable with C++17 or above."); | ||
} | ||
|
||
#endif | ||
ABSL_NAMESPACE_END | ||
} // namespace absl | ||
|
||
#endif // ABSL_FUNCTIONAL_OVERLOAD_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// Copyright 2023 The Abseil Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include "absl/functional/overload.h" | ||
|
||
#include <cstdint> | ||
#include <string> | ||
#include <type_traits> | ||
|
||
#include "absl/base/config.h" | ||
#include "absl/strings/str_cat.h" | ||
#include "absl/strings/string_view.h" | ||
#include "absl/types/variant.h" | ||
|
||
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ | ||
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L | ||
|
||
#include "gtest/gtest.h" | ||
|
||
namespace { | ||
|
||
TEST(OverloadTest, DispatchConsidersType) { | ||
auto overloaded = absl::Overload( | ||
[](int v) -> std::string { return absl::StrCat("int ", v); }, // | ||
[](double v) -> std::string { return absl::StrCat("double ", v); }, // | ||
[](const char* v) -> std::string { // | ||
return absl::StrCat("const char* ", v); // | ||
}, // | ||
[](auto v) -> std::string { return absl::StrCat("auto ", v); } // | ||
); | ||
EXPECT_EQ("int 1", overloaded(1)); | ||
EXPECT_EQ("double 2.5", overloaded(2.5)); | ||
EXPECT_EQ("const char* hello", overloaded("hello")); | ||
EXPECT_EQ("auto 1.5", overloaded(1.5f)); | ||
} | ||
|
||
TEST(OverloadTest, DispatchConsidersNumberOfArguments) { | ||
auto overloaded = absl::Overload( // | ||
[](int a) { return a + 1; }, // | ||
[](int a, int b) { return a * b; }, // | ||
[]() -> absl::string_view { return "none"; } // | ||
); | ||
EXPECT_EQ(3, overloaded(2)); | ||
EXPECT_EQ(21, overloaded(3, 7)); | ||
EXPECT_EQ("none", overloaded()); | ||
} | ||
|
||
TEST(OverloadTest, SupportsConstantEvaluation) { | ||
auto overloaded = absl::Overload( // | ||
[](int a) { return a + 1; }, // | ||
[](int a, int b) { return a * b; }, // | ||
[]() -> absl::string_view { return "none"; } // | ||
); | ||
static_assert(overloaded() == "none"); | ||
static_assert(overloaded(2) == 3); | ||
static_assert(overloaded(3, 7) == 21); | ||
} | ||
|
||
TEST(OverloadTest, PropogatesDefaults) { | ||
auto overloaded = absl::Overload( // | ||
[](int a, int b = 5) { return a * b; }, // | ||
[](double c) { return c; } // | ||
); | ||
|
||
EXPECT_EQ(21, overloaded(3, 7)); | ||
EXPECT_EQ(35, overloaded(7)); | ||
EXPECT_EQ(2.5, overloaded(2.5)); | ||
} | ||
|
||
TEST(OverloadTest, AmbiguousWithDefaultsNotInvocable) { | ||
auto overloaded = absl::Overload( // | ||
[](int a, int b = 5) { return a * b; }, // | ||
[](int c) { return c; } // | ||
); | ||
static_assert(!std::is_invocable_v<decltype(overloaded), int>); | ||
static_assert(std::is_invocable_v<decltype(overloaded), int, int>); | ||
} | ||
|
||
TEST(OverloadTest, AmbiguousDuplicatesNotInvocable) { | ||
auto overloaded = absl::Overload( // | ||
[](int a) { return a; }, // | ||
[](int c) { return c; } // | ||
); | ||
static_assert(!std::is_invocable_v<decltype(overloaded), int>); | ||
} | ||
|
||
TEST(OverloadTest, AmbiguousConversionNotInvocable) { | ||
auto overloaded = absl::Overload( // | ||
[](uint16_t a) { return a; }, // | ||
[](uint64_t c) { return c; } // | ||
); | ||
static_assert(!std::is_invocable_v<decltype(overloaded), int>); | ||
} | ||
|
||
TEST(OverloadTest, DispatchConsidersSfinae) { | ||
auto overloaded = absl::Overload( // | ||
[](auto a) -> decltype(a + 1) { return a + 1; } // | ||
); | ||
static_assert(std::is_invocable_v<decltype(overloaded), int>); | ||
static_assert(!std::is_invocable_v<decltype(overloaded), std::string>); | ||
} | ||
|
||
TEST(OverloadTest, VariantVisitDispatchesCorrectly) { | ||
absl::variant<int, double, std::string> v(1); | ||
auto overloaded = absl::Overload( | ||
[](int) -> absl::string_view { return "int"; }, // | ||
[](double) -> absl::string_view { return "double"; }, // | ||
[](const std::string&) -> absl::string_view { return "string"; } // | ||
); | ||
EXPECT_EQ("int", absl::visit(overloaded, v)); | ||
v = 1.1; | ||
EXPECT_EQ("double", absl::visit(overloaded, v)); | ||
v = "hello"; | ||
EXPECT_EQ("string", absl::visit(overloaded, v)); | ||
} | ||
|
||
} // namespace | ||
|
||
#endif |