Is there a way to implement universal and existential quantification using C++ template magic (maybe using SFINAE etc.)? Something like this:
template
<
template <typename Argument> class Predicate
>
struct UniversalQuantification
{
static const bool value =
/*for any Argument Predicate<Argument>::value == true ? true : false*/;
};
template
<
template <typename Argument> class Predicate
>
struct ExistentialQuantification
{
static const bool value =
/*for some Argument Predicate<Argument>::value == true ? true : false*/;
};
If you pass a finite set of possible template arguments to the template, it is indeed possible to evaluate this at compile-time. However, it is impossible to evaluate this for every argument the passed template has been used with, as these types/args are unknown.
This is the solution for a finite set of arguments for the ExistentialQuantification
class. In order to achieve the behaviour of the UniversalQuantification
class, you simple have to change the ||
to a &&
:
template<typename Arg>
struct Pred1;
template<>
struct Pred1<float> { static const bool value = true; };
template<>
struct Pred1<double> { static const bool value = false; };
template<>
struct Pred1<long> { static const bool value = true; };
template<template <typename Argument> class Predicate, typename... Types>
struct ExistentialQuantification;
template<template <typename Argument> class Predicate, typename Arg>
struct ExistentialQuantification<Predicate, Arg>
{
static const bool value = Predicate<Arg>::value;
};
template<template <typename Argument> class Predicate, typename Arg, typename... Types>
struct ExistentialQuantification<Predicate, Arg, Types...>
{
static const bool value = Predicate<Arg>::value || ExistentialQuantification<Predicate, Types...>::value;
};
int main()
{
std::cout << ExistentialQuantification<Pred1, long, double, float>::value << std::endl;
}
In this example, value
will evaluate to true || false || true
and is thus true of course.
Ok, if we're just being smart here, and if we're allowed a couple of constraints, here are two constraints on the programmer, that really solve the problem, smoothly.
if a predicate is needed in the code that is always true, only use the following:
template<typename> struct always : std::true_type { };
if a predicate is needed in the code that is never true, only use the following:
template<typename> struct never : std::false_type { };
Now, the solution is simple:
template<template<typename> class>
struct UniversalQuantification : std::false_type { };
template<>
struct UniversalQuantification<always> : std::true_type { };
template<template<typename> class>
struct ExistentialQuantification : std::true_type { };
template<>
struct ExistentialQuantification<never> : std::false_type { };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With