Есть ли способ реализовать универсальный а также экзистенциальный количественная оценка с использованием магии шаблонов 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*/;
};
Если вы передаете конечный набор возможных аргументов шаблона для шаблона, действительно возможно оценить это во время компиляции. Однако это невозможно оценить для каждого аргумента, с которым был передан шаблон, так как эти типы / аргументы неизвестны.
Это решение для конечного набора аргументов для 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
и, таким образом, это правда, конечно.
Хорошо, если мы просто умны здесь, и если нам разрешают пару ограничений, вот два ограничения для программиста, которые действительно решают проблему, плавно.
если в коде нужен предикат, который всегда имеет значение true, используйте только следующее:
template<typename> struct always : std::true_type { };
если в коде нужен предикат, который никогда не верен, используйте только следующее:
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 { };
Использование библиотеки как 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
как базовый класс, экзистенциальное количественное определение успешно.
Хорошо, если мы просто говорим о 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 { };