Универсальное и экзистенциальное количественное определение с использованием магии шаблона C ++

Есть ли способ реализовать универсальный а также экзистенциальный количественная оценка с использованием магии шаблонов C ++ (возможно, с использованием SFINAE и т. д.)? Что-то вроде этого:

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*/;
};

4

Решение

Если вы передаете конечный набор возможных аргументов шаблона для шаблона, действительно возможно оценить это во время компиляции. Однако это невозможно оценить для каждого аргумента, с которым был передан шаблон, так как эти типы / аргументы неизвестны.

Это решение для конечного набора аргументов для ExistentialQuantification учебный класс. Для того, чтобы достичь поведения UniversalQuantification класс, вы просто должны изменить || к &&:

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;
}

В этом примере value будет оценивать true || false || true и, таким образом, это правда, конечно.

3

Другие решения

Хорошо, если мы просто умны здесь, и если нам разрешают пару ограничений, вот два ограничения для программиста, которые действительно решают проблему, плавно.

  1. если в коде нужен предикат, который всегда имеет значение true, используйте только следующее:

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

  2. если в коде нужен предикат, который никогда не верен, используйте только следующее:

    template<typename> struct never : std::false_type { };

Теперь решение простое:

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 { };
3

Использование библиотеки как Boost.MPL, если вы можете поместить свою вселенную разрешенных типов в список типов, например, в boost::mpl::vectorто ваши квантификаторы — это всего лишь версия времени компиляции std::all_of а также std::any_of, Вы можете определить их как:

#include <ios>
#include <iostream>
#include <type_traits>                  // is_same, is_base_of
#include <boost/mpl/end.hpp>            // end
#include <boost/mpl/find_if.hpp>        // find_if
#include <boost/mpl/lambda.hpp>         // lambda
#include <boost/mpl/logical.hpp>        // not_
#include <boost/mpl/placeholders.hpp>   // _1
#include <boost/mpl/vector.hpp>         // vector

template<typename Sequence, typename Pred>
struct all_of
:
std::is_same< typename
boost::mpl::find_if<
Sequence,
boost::mpl::not_<Pred>
>::type, typename
boost::mpl::end<Sequence>::type
>
{};

template<typename Sequence, typename Pred>
struct none_of
:
all_of< Sequence, boost::mpl::not_< Pred > >
{};

template<typename Sequence, typename Pred>
struct any_of
:
boost::mpl::not_< none_of< Sequence, Pred > >
{};

struct B {};
struct D : B {};
struct X {};

using Universe = boost::mpl::vector<B, D, X>;
using Predicate = boost::mpl::lambda<std::is_base_of<B, boost::mpl::_1>>;

int main()
{
std::cout << std::boolalpha;
std::cout << all_of<Universe, Predicate>{} << "\n";
std::cout << any_of<Universe, Predicate>{} << "\n";
}

Живой пример.

Как видите, потому что X не имеет B как базовый класс, универсальное количественное определение не удается, но потому что D имеет B как базовый класс, экзистенциальное количественное определение успешно.

1

Хорошо, если мы просто говорим о n-арных (вариадических) функциях а также, или же как в ответе TemplateRex, вот мой любимый способ без Boost:

using _true  = std::integral_constant <bool, true>;
using _false = std::integral_constant <bool, false>;

template <bool C, typename T, typename E>
using _if = typename std::conditional <C, T, E>::type;

template <typename...> struct _and;
template <typename...> struct _or;

template <typename A, typename... B>
struct _and <A, B...> : _if <A{}, _and <B...>, _false> { };

template <typename A, typename... B>
struct _or <A, B...> : _if <A{}, _true, _or <B...> > { };

template <> struct _and <> : _true { };
template <> struct _or <> : _false { };
1
По вопросам рекламы [email protected]