Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Universal and existential quantification using C++ template magic

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*/;
};
like image 537
Constructor Avatar asked Feb 13 '23 09:02

Constructor


2 Answers

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.

like image 69
Sebastian Hoffmann Avatar answered Feb 16 '23 02:02

Sebastian Hoffmann


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.

  1. if a predicate is needed in the code that is always true, only use the following:

    template<typename> struct always : std::true_type { };

  2. 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 { };
like image 23
iavr Avatar answered Feb 16 '23 02:02

iavr