Deduce the template parameter of a variant based on every return path. Ideally, the C++ language would provide something like:
std::variant auto func(bool ok)
{
if (ok)
return 1.5f;
return "example";
}
static_assert(std::is_same_v<decltype(func()), std::variant<float, const char*>>);
This library attempts to mimic such functionality with minimal boilerplate and (zero) overhead:
auto func(bool ok)
{
static constexpr dehe::Variate var;
if (ok)
return var(1.5f);
return var("example");
}
static_assert(std::is_same_v<decltype(dehe::make_variant(func())), std::variant<float, const char*>>);
Play with it on godbolt.
With the advent of std::execution, C++ developers are faced with more and more unnamable types. All sender types are considered implementation details and can only be identified using something like decltype(std::execution::just(42))
. Additionally, we often must write functional-style code when dealing with std::execution
, meaning we must return the same sender type from all return paths of our functions. This makes it difficult to express conditional branches. Libunifex provides a variant_sender
class template that we can hook into this library to ease the process:
// Code to bridge unifex to this library
static constexpr auto variant_sender_factory = []<std::size_t, class... T, class Arg>(Arg && arg)
{
return unifex::variant_sender<T...>{std::forward<Arg>(arg)};
};
auto make_variant_sender(auto&& erased)
{
return dehe::make(std::forward<decltype(erased)>(erased), variant_sender_factory);
}
// Our actual business logic containing branches. Without this library we would need to spell out the return type:
// `unifex::variant_sender<decltype(unifex::just(5)), decltype(unifex::just() | unifex::then(lambda))>`
// and move the lambda into a separate place.
auto business_logic(bool ok)
{
static constexpr dehe::Variate var;
if (ok)
{
return var(unifex::just(5));
}
return var(unifex::just() | unifex::then(
[]
{
return 42;
}));
}
// Imagine some chain of senders:
| unifex::let_value([](bool ok)
{
return make_variant_sender(business_logic(ok));
});
Copy the headers from src/variate
into your project.
Alternatively, use CMake to install the project. From the root of the repository:
cmake -B build -S .
cmake --install build --prefix build/out
And in your CMake project's CMakeLists.txt:
# Add build/out to the CMAKE_PREFIX_PATH
find_package(variate)
target_link_libraries(my_app PRIVATE variate::variate)
Include the single header:
#include <variate/variate.hpp>
The only requirement is a small subset of C++20.
The following compilers are continuously tested by Github Actions:
- GCC 10
- Clang 12
- MSVC 19.34
- AppleClang 14