4

有没有办法使用 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

4 回答 4

3

如果您将一组有限的可能模板参数传递给模板,则确实可以在编译时对其进行评估。但是,不可能对传递的模板已使用的每个参数进行评估,因为这些类型/参数是未知的。

这是ExistentialQuantification该类的有限参数集的解决方案。为了实现UniversalQuantification类的行为,您只需将 更改||为 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;
}

在此示例中,value将评估为true || false || true,因此当然是正确的。

于 2014-03-25T19:21:52.410 回答
3

好吧,如果我们只是聪明一点,如果我们被允许有几个约束,这里有两个对程序员的约束,它们确实可以顺利地解决问题。

  1. 如果代码中需要一个始终为真的谓词,请仅使用以下语句:

    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 { };
于 2014-03-25T20:16:41.820 回答
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 { };
于 2014-03-25T19:24:21.533 回答
1

使用像Boost.MPL这样的库,如果您可以将允许类型的世界放入类型列表中,例如在 a 中boost::mpl::vector,那么您的量词只是std::all_ofand的编译时版本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作为基类,所以全称量化失败了,但是因为DB作为基类,存在量化成功了。

于 2014-03-25T19:12:41.130 回答