I use a lot of std::variants. I have this trusty helper concept that matches alternatives of a specific variant type:
template<typename alternative_type, typename variant_type>
struct alternative_c_impl {
static_assert(false, "can't use is_alternative<> with a non-variant"); // legal in C++23
};
template<typename alternative_type, typename... variant_alternatives>
struct alternative_c_impl<alternative_type, std::variant<variant_alternatives...>>
: std::disjunction<std::is_same<alternative_type, variant_alternatives>...>
{};
template<typename alternative_type, typename variant_type>
concept alternative_c = alternative_c_impl<alternative_type, variant_type>::value;
auto main() -> int
{
using simple_variant = std::variant<int, float>;
static_assert(alternative_c<int, simple_variant>);
static_assert(alternative_c<std::string, simple_variant> == false);
}
However in C++23, we can now have types derived from std::variant. For such, this approach fails expectedly with the initial static_assert. My template skills got a little rusty and I'm having trouble expanding this to work with such a type. I guess it somehow involves std::derived_from. Speaking in code, I want a mystery_c concept that works analogously:
struct derived_var : std::variant<int, float>
{
};
auto main() -> int
{
static_assert(mystery_c<int, derived_var>);
static_assert(mystery_c<std::string, derived_var> == false);
}
You can define a concept that attempts to deduce an instantiation of
std::variantfrom an instance of theTVariantas a function parameter, allowing base-class conversion, and then use a fold expression to testTAlternativeagainst each type in the template parameter pack deduced for the instantiation:Since this approach doesn't require support for lambdas in unevaluated contexts, it will work with all compilers that support C++20 concepts, starting with Clang 10, GCC 10, and MSVC 19.30:
https://godbolt.org/z/9c7qzo1sd